杰瑞科技汇

如何基于MVC开发Java Web应用?

目录

  1. 什么是MVC模式? - 核心思想与定义
  2. 为什么在Java Web中使用MVC? - 优势与解决的问题
  3. MVC在Java Web中的具体角色 - Model, View, Controller 各司其职
  4. 一个典型的Java Web MVC请求流程 - 从用户输入到看到结果
  5. Java Web MVC的演进 - 从Servlet到Spring Framework
  6. 实践案例:一个简单的用户登录示例 - 代码与步骤
  7. 总结与展望

什么是MVC模式?

MVC是一种软件设计架构模式,旨在将一个应用程序划分为三个相互关联的部分,以实现关注点分离。

如何基于MVC开发Java Web应用?-图1
(图片来源网络,侵删)
  • M - Model (模型):

    • 职责: 负责数据和业务逻辑,它是应用程序的核心。
    • 数据库操作、业务规则计算、数据状态管理等,它不关心数据如何被展示。
    • 例子: 一个 User 类,包含 id, username, password 等属性,以及一个 UserService 类负责处理用户注册、登录等逻辑。
  • V - View (视图):

    • 职责: 负责数据显示和用户交互,它是用户看到并与之交互的界面。
    • HTML, JSP, Thymeleaf, FreeMarker等模板文件,它只负责从 Model 中获取数据并展示,不包含任何业务逻辑。
    • 例子: 一个 login.jsp 页面,包含用户名和密码的输入框,以及一个“登录”按钮。
  • C - Controller (控制器):

    • 职责: 接收用户请求,调用 Model 处理业务逻辑,然后选择一个 View 来展示结果,它是 ModelView 之间的协调者。
    • 接收HTTP请求,解析参数,调用相应的服务(Model),并将处理结果(数据)传递给 View 进行渲染。
    • 例子: 一个 LoginServletLoginController,它接收登录请求,调用 UserService 验证用户,然后根据验证结果决定是跳转到欢迎页面还是登录失败页面。

核心思想: 用户通过 View 发起请求,Controller 接收并处理,Model 负责核心业务,Controller 选择一个 View 将结果呈现给用户,这三者各司其职,降低了代码的耦合度。

如何基于MVC开发Java Web应用?-图2
(图片来源网络,侵删)

为什么在Java Web中使用MVC?

在MVC模式出现之前,Java Web开发常常是“Model 1”模式,即JSP页面中既包含HTML展示代码,又嵌入Java代码(脚本片段Scriptlets)来处理业务逻辑,这导致了:

  • 代码混乱: HTML和Java代码混在一起,难以维护。
  • 职责不清: JSP页面承担了太多责任,既管显示又管逻辑。
  • 难以测试: 业务逻辑与视图紧密耦合,无法单独对业务逻辑进行单元测试。

MVC模式完美地解决了这些问题:

  • 职责分离: 代码结构清晰,Model, View, Controller 各司其职。
  • 可维护性高: 修改业务逻辑不会影响视图,修改视图也不会影响业务逻辑。
  • 可复用性强: Model的业务逻辑可以被不同的View(例如网页、App接口)复用。
  • 可扩展性好: 可以轻松地更换视图技术(例如从JSP换成Thymeleaf)或增加新的控制器。
  • 易于测试: Model的业务逻辑可以独立进行单元测试。

MVC在Java Web中的具体角色

我们来更具体地看看这三个角色在Java Web技术栈中通常对应什么。

角色 职责 常见技术实现
Model (模型) - 数据对象: POJO (Plain Old Java Object),如 User.java, Product.java
- 业务逻辑/服务: 处理核心业务,如 UserService.java, OrderService.java
- 数据访问层: 与数据库交互,如 UserDAO.java (Data Access Object)。
- JavaBeans/POJOs
- Spring Service (带有 @Service 注解)
- JPA/Hibernate Entities (带有 @Entity 注解)
- MyBatis Mapper
View (视图) - 渲染数据: 接收来自Controller的数据,并将其转换为用户可见的格式(HTML、JSON等)。
- 提供用户界面: 包含HTML、CSS、JavaScript等。
- JSP / JSTL: 经典的Java视图技术。
- Thymeleaf: 现代化的、优雅的服务器端模板引擎。
- FreeMarker: 另一个流行的模板引擎。
- JSON/XML: 用于构建RESTful API的视图。
Controller (控制器) - 请求入口: 接收所有来自客户端的HTTP请求。
- 参数解析: 从请求中提取参数(如URL路径、查询参数、表单数据)。
- 业务调度: 调用Model中的业务逻辑方法处理请求。
- 结果响应: 根据业务处理结果,选择合适的View进行响应,或直接返回数据(如JSON)。
- Servlet: 最原始、最底层的控制器实现。
- Spring MVC Controller (带有 @Controller 注解): 现代Java Web开发的主流,功能强大,使用方便。

一个典型的Java Web MVC请求流程

假设用户点击了“登录”按钮,一个典型的MVC请求流程如下:

如何基于MVC开发Java Web应用?-图3
(图片来源网络,侵删)
  1. 用户发起请求: 用户在浏览器中填写登录表单并点击提交,浏览器向服务器发送一个HTTP POST请求,http://example.com/login

  2. Controller接收请求: 前端控制器(在Spring中是 DispatcherServlet)接收到这个请求,它会根据URL配置,将请求转发给相应的 Controller 方法(LoginController 中的 handleLogin 方法)。

  3. Controller处理请求:

    • Controller 方法从HTTP请求中获取用户名和密码参数。
    • 不自己去验证用户,而是调用 Model 层的 UserService,并传入用户名和密码。
      UserService userService = new UserService();
      User user = userService.login(username, password);
    • UserService 执行数据库查询和密码比对等业务逻辑,然后将结果(User对象或null)返回给 Controller
  4. Controller选择View:

    • Controller 根据 UserService 返回的结果做决定。
    • 如果登录成功:
      • 它可以将用户信息存入 Session
      • 它选择一个“欢迎页”作为 View,并将用户信息作为数据传递给这个 View
    • 如果登录失败:
      • 它选择一个“登录页”作为 View,并将一个错误信息(如“用户名或密码错误”)传递给这个 View
  5. View渲染响应:

    • 选定的 View(例如一个JSP页面)接收到从 Controller 传来的数据。
    • 它使用JSTL或EL表达式等技术,将数据动态地嵌入到HTML模板中。
    • 欢迎页可能会显示“欢迎您,${user.username}!”。
    • View 生成完整的HTML文档。
  6. 服务器响应浏览器: 服务器将生成的HTML文档作为HTTP响应发送回用户的浏览器,浏览器解析并渲染HTML,用户最终看到登录成功或失败的页面。


Java Web MVC的演进

Java Web MVC的实现方式随着技术的发展不断演进:

  • 原生Servlet (早期)

    • 特点: 所有的控制器逻辑都写在 doGet()doPost() 方法中,需要手动获取参数、手动调用业务逻辑、手动跳转页面。
    • 缺点: 代码冗余,配置繁琐,一个Servlet只能处理一个功能,扩展性差。
  • MVC框架 (如Struts1, Struts2)

    • 特点: 引入了前端控制器模式,所有请求都先到一个核心控制器,再由它分发到具体的业务Action(控制器),提供了更清晰的MVC结构和更丰富的功能。
    • 缺点: 配置文件复杂,侵入性强(代码需要继承特定框架的类),学习曲线陡峭。
  • 现代MVC框架 (如Spring MVC)

    • 特点: 基于注解(Annotation)驱动,配置非常简洁(通常只需在方法上加上 @RequestMapping),控制器是普通的POJO,耦合度极低,与Spring IoC容器无缝集成,依赖注入非常方便。
    • 现状: 这是目前Java Web开发的主流和标准,Spring Boot更是极大地简化了Spring MVC项目的创建和配置。

实践案例:一个简单的用户登录示例

我们使用 Spring MVC 来构建一个简单的登录功能。

项目结构:

src
└── main
    ├── java
    │   └── com.example.demo
    │       ├── controller
    │       │   └── LoginController.java
    │       ├── model
    │       │   ├── User.java
    │       │   └── service
    │       │       └── UserService.java
    │       └── DemoApplication.java
    ├── resources
    │   └── application.properties
    └── webapp
        ├── WEB-INF
        │   └── views
        │       ├── home.jsp
        │       └── login.jsp
        └── index.jsp

步骤1: Model (模型)

User.java (数据对象)

package com.example.demo.model;
public class User {
    private String username;
    private String password;
    // Getters and Setters
    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }
    public String getPassword() { return password; }
    public void setPassword(String password) { this.password = password; }
}

UserService.java (业务逻辑)

package com.example.demo.model.service;
import com.example.demo.model.User;
import org.springframework.stereotype.Service;
@Service // 告诉Spring这是一个服务类,需要被管理
public class UserService {
    public User login(String username, String password) {
        // 这里是模拟的业务逻辑,实际项目中会查询数据库
        if ("admin".equals(username) && "password123".equals(password)) {
            User user = new User();
            user.setUsername(username);
            return user;
        }
        return null; // 登录失败
    }
}

步骤2: View (视图)

login.jsp (登录页面)

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>登录</title>
</head>
<body>
    <h1>用户登录</h1>
    <form action="/login" method="post">
        用户名: <input type="text" name="username"><br>
        密码: <input type="password" name="password"><br>
        <input type="submit" value="登录">
    </form>
</body>
</html>

home.jsp (登录成功后的首页)

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>首页</title>
</head>
<body>
    <h1>欢迎您, ${user.username}!</h1>
</body>
</html>

步骤3: Controller (控制器)

LoginController.java

package com.example.demo.controller;
import com.example.demo.model.User;
import com.example.demo.model.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.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller // 告诉Spring这是一个控制器
public class LoginController {
    @Autowired // 自动注入UserService,由Spring IoC容器提供实例
    private UserService userService;
    // 处理登录页面的GET请求,直接显示登录页
    @GetMapping("/login")
    public String showLoginPage() {
        return "login"; // 返回视图名,Spring会解析为 /WEB-INF/views/login.jsp
    }
    // 处理登录表单的POST请求
    @PostMapping("/login")
    public String handleLogin(
            @RequestParam("username") String username,
            @RequestParam("password") String password,
            Model model) { // Model用于向视图传递数据
        User user = userService.login(username, password);
        if (user != null) {
            // 登录成功,将用户信息存入Model
            model.addAttribute("user", user);
            return "home"; // 跳转到首页
        } else {
            // 登录失败,可以向Model中添加错误信息,并返回登录页
            model.addAttribute("error", "用户名或密码错误");
            return "login";
        }
    }
}

步骤4: 配置与启动

application.properties (Spring Boot配置)

# 服务器端口
server.port=8080
# 视图解析器配置
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp

DemoApplication.java (Spring Boot启动类)

package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

运行流程总结:

  1. 启动 DemoApplication,Spring Boot启动内嵌Tomcat服务器。
  2. 用户访问 http://localhost:8080/login
  3. LoginController.showLoginPage() 被执行,返回 "login"
  4. Spring的视图解析器找到 /WEB-INF/views/login.jsp 并渲染,用户看到登录页面。
  5. 用户输入 admin / password123 并提交表单。
  6. 请求以POST方式发送到 /login
  7. LoginController.handleLogin() 被执行。
  8. userService.login() 被调用,返回一个 User 对象。
  9. handleLogin()User 对象存入 Model,并返回 "home"
  10. Spring视图解析器找到 /WEB-INF/views/home.jsp,使用 Model 中的数据渲染页面。
  11. 浏览器收到渲染后的HTML,显示“欢迎您, admin!”。

总结与展望

基于MVC的Java Web开发是一种成熟、强大且结构化的开发模式,它通过将应用程序分解为Model、View和Controller三个部分,实现了高度的职责分离,使得代码更易于理解、维护、测试和扩展,从原始的Servlet到现代的Spring MVC,该模式的核心思想一直被传承和发扬,是每一位Java Web开发者必须掌握的核心知识。

展望: 虽然MVC模式非常经典,但现代Web开发也在不断演进:

  • 前后端分离: 越来越多的项目采用前后端分离架构。View层完全由前端框架(如Vue.js, React, Angular)负责,运行在浏览器中,后端的 ControllerModel 则通过提供RESTful API(通常返回JSON数据)来与前端通信,这种模式下,后端的MVC模式依然存在,但View的角色被API接口取代。
  • 新架构模式: 对于一些复杂的单页应用,一些新的架构模式如MVVM (Model-View-ViewModel) 也开始流行,它进一步增强了View和Model的解耦。

尽管如此,MVC所蕴含的“关注点分离”的哲学思想,依然是现代软件设计的基石,掌握MVC,是理解更复杂架构的第一步。

分享:
扫描分享到社交APP
上一篇
下一篇