Servlet 和 Spring MVC:区别与联系

前言

在 Java Web 开发中,Servlet 和 Spring MVC 是两个重要的技术。Servlet 是 Java Web 的基础组件,而 Spring MVC 是一个高级 Web 框架,建立在 Servlet 的基础之上,提供了强大的功能和易用性。这篇文章将从定义、原理、功能对比、应用场景等多个方面,详细介绍 Servlet 和 Spring MVC,并解析它们的区别与联系。


一、什么是 Servlet

1. 定义

Servlet 是 Java Web 应用的核心组件,是一种运行在服务器上的小程序,专门用于处理客户端的 HTTP 请求并生成动态响应。Servlet 是 Java EE 规范的一部分,定义了如何通过 Java 编写服务器端的 Web 应用。

2. 工作原理

Servlet 的核心思想是基于 请求-响应模型

  1. 客户端(通常是浏览器)发送 HTTP 请求。
  2. Web 容器(如 Tomcat)将请求路由到 Servlet。
  3. Servlet 处理请求,执行逻辑,生成并返回 HTTP 响应。

3. 核心组件

  • HttpServletRequest:表示客户端的请求对象,包含请求的所有信息(如请求参数、请求头等)。
  • HttpServletResponse:表示服务器的响应对象,包含响应的所有信息(如响应头、响应状态码、响应体等)。

4. Servlet 的生命周期

Servlet 的生命周期由 Web 容器管理,包含以下几个阶段:

  1. 初始化
    • Servlet 第一次被访问时,容器会加载 Servlet 类并调用 init() 方法完成初始化。
  2. 服务
    • 每次请求都会调用 service() 方法,根据请求的 HTTP 方法(GET、POST 等),调用对应的 doGet()doPost() 方法。
  3. 销毁
    • 在服务器关闭或卸载 Servlet 时,调用 destroy() 方法释放资源。

5. 示例代码

以下是一个简单的 Servlet 示例:

@WebServlet("/hello")
public class HelloServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {// 设置响应内容类型resp.setContentType("text/html");// 返回简单的 HTML 响应resp.getWriter().write("<h1>Hello, Servlet!</h1>");}
}

二、什么是 Spring MVC

1. 定义

Spring MVC 是基于 Spring 框架的一个 Web 开发模块,提供了 MVC(Model-View-Controller) 设计模式的完整实现。它简化了 Web 应用开发,提供了对请求映射、参数绑定、视图解析等功能的强大支持。

2. 核心思想

Spring MVC 通过 DispatcherServlet(前端控制器)将所有请求统一拦截并分发给具体的处理器(Controller),然后结合视图(View)生成响应。


3. Spring MVC 的架构

Spring MVC 的核心组件:

  1. DispatcherServlet
    • 前端控制器,负责接收和分发所有 HTTP 请求。
  2. HandlerMapping
    • 请求映射器,将 URL 映射到具体的控制器方法。
  3. Controller
    • 业务处理器,负责执行具体的逻辑。
  4. ModelAndView
    • 数据模型和视图对象,用于封装业务数据和返回的视图信息。
  5. ViewResolver
    • 视图解析器,将逻辑视图名解析为物理视图(如 JSP、Thymeleaf 页面)。
  6. View
    • 负责生成最终的响应内容(HTML、JSON 等)。

4. 工作流程

Spring MVC的工作流程_spring mvc 的工作流程-CSDN博客

  1. 客户端发送请求。
  2. DispatcherServlet 接收请求并委托给 HandlerMapping 找到对应的 Controller 方法。
  3. Controller 方法处理请求,返回数据(Model)和视图(View)。
  4. ViewResolver 将逻辑视图名解析为物理视图。
  5. 将数据渲染到视图,生成响应并返回给客户端。

5. 示例代码

以下是一个简单的 Spring MVC 示例:

Controller 类:

@Controller
public class HelloController {@GetMapping("/hello")@ResponseBodypublic String sayHello(@RequestParam String name) {return "<h1>Hello, " + name + "!</h1>";}
}

三、Servlet 和 Spring MVC 的区别

对比维度ServletSpring MVC
定位Java Web 开发的基础技术。基于 Servlet 构建的高级 Web 框架。
设计思想直接基于 HTTP 请求-响应模型。基于 MVC(Model-View-Controller)设计模式。
开发复杂度较高,需要手动解析请求和生成响应。较低,提供自动化功能(如参数绑定、视图解析)。
功能丰富度功能较少,需要自行实现扩展(如请求映射、数据绑定)。功能丰富,内置请求映射、表单验证、异常处理等功能。
请求映射静态 URL 映射,直接通过 Web 容器配置路由。灵活的动态映射,支持正则表达式、RESTful URL 等。
视图支持需要手动拼接 HTML 或 JSP 页面。支持多种视图技术(JSP、Thymeleaf、JSON 等)。
表单验证需要手动校验参数。提供注解式校验(如 @Valid@NotNull)。
异常处理需要在代码中显式捕获异常并处理。提供全局异常处理机制(如 @ControllerAdvice)。
扩展性扩展性有限,需通过 Filter 或 Listener 实现一些通用功能。提供拦截器机制,支持 AOP 和依赖注入,扩展性极强。
学习曲线入门简单,但复杂项目开发难度大。需要学习 Spring 框架基础,初学者学习曲线稍陡。
适用场景小型项目或需要直接操作 HTTP 请求的场景。中大型项目,特别是需要高扩展性和快速开发的场景。

四、Servlet 和 Spring MVC 的联系

尽管 Servlet 和 Spring MVC 在定位和功能上有所不同,但它们之间有着密切的联系:

1. 基于 Servlet 构建

  • Spring MVC 是构建在 Servlet 基础之上的高级框架。
  • Spring MVC 的核心组件 DispatcherServlet 本质上是一个 Servlet,它负责接收和分发请求。

2. Servlet 是 Spring MVC 的基础

  • Spring MVC 使用 Servlet 来处理 HTTP 请求,但屏蔽了复杂的细节,例如参数解析、请求分发等。

3. Spring MVC 依赖 Servlet 容器

  • Spring MVC 必须运行在支持 Servlet 的 Web 容器(如 Tomcat、Jetty)中。
  • Servlet 容器负责加载和管理 DispatcherServlet

五、什么时候选择 Servlet 或 Spring MVC

1. 使用 Servlet

  • 适合小型项目,功能简单。
  • 希望深入理解 Java Web 的底层原理。
  • 不需要复杂的框架支持,能够手动实现请求处理和响应。

2. 使用 Spring MVC

  • 适合中大型项目,功能复杂。
  • 需要高效开发、灵活配置和良好的扩展能力。
  • 希望享受 Spring 框架的生态系统(如 Spring Data、Spring Security 等)。

示例代码

假设我们需要构建一个简单的 Web 服务:

  • 请求路径:http://localhost:8080/hello?name=Tom
  • 返回内容:Hello, Tom!

完整 Servlet 实现

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;// 使用 @WebServlet 注解映射路径 "/hello"
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {// 初始化 Servlet(只执行一次)@Overridepublic void init() throws ServletException {super.init();System.out.println("Servlet 初始化完成!");}// 处理 GET 请求@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 设置响应内容类型resp.setContentType("text/html;charset=UTF-8");// 获取请求参数String name = req.getParameter("name");if (name == null || name.isEmpty()) {name = "World"; // 默认值}// 返回动态响应resp.getWriter().write("<h1>Hello, " + name + "!</h1>");}// 销毁 Servlet(只执行一次,用于释放资源)@Overridepublic void destroy() {super.destroy();System.out.println("Servlet 已被销毁!");}
}

代码优化点

  1. 注解简化配置:
    • 使用 @WebServlet 注解代替传统的 web.xml 配置。
  2. 默认参数处理:
    • 如果用户未传递参数,返回默认的 "World"。
  3. 字符编码:
    • 通过 resp.setContentType("text/html;charset=UTF-8") 设置字符编码,防止中文乱码。
  4. 日志输出:
    • init()destroy() 方法中添加日志信息,便于调试。

如何运行

  1. 将代码打包为 .war 文件,并部署到 Tomcat。
  2. 访问 URL:http://localhost:8080/hello?name=Tom
  3. 返回结果:Hello, Tom!

Spring MVC 实现

Spring MVC 的实现更加简洁且功能强大。以下代码实现相同的功能。

Controller 类

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;@Controller
public class HelloController {// 处理 GET 请求,映射路径 "/hello"@GetMapping("/hello")@ResponseBodypublic String sayHello(@RequestParam(name = "name", required = false, defaultValue = "World") String name) {// 返回动态内容return "<h1>Hello, " + name + "!</h1>";}
}

Spring Boot 主类

如果使用 Spring Boot 构建项目,可以通过以下代码快速启动:

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

代码优化点

  1. 注解驱动开发:
    • 使用 @Controller@GetMapping 注解处理请求,简化了配置。
  2. 自动参数绑定:
    • 使用 @RequestParam 自动从请求中提取参数,同时设置默认值。
  3. 自动响应:
    • 通过 @ResponseBody 将返回的字符串直接作为响应体,省去了手动处理 HttpServletResponse
  4. Spring Boot 快速启动:
    • 使用 Spring Boot 自动化配置,无需单独部署到 Tomcat。

如何运行

  1. 将代码保存为一个 Spring Boot 应用。
  2. 运行主类 SpringMvcApplication
  3. 访问 URL:http://localhost:8080/hello?name=Tom
  4. 返回结果:Hello, Tom!

示例场景扩展

为了更好地理解 Servlet 和 Spring MVC 的应用场景,我们再扩展一个功能:根据用户输入返回 JSON 数据。

Servlet 示例(返回 JSON 数据)

import com.google.gson.Gson;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;@WebServlet("/json")
public class JsonServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 设置响应类型为 JSONresp.setContentType("application/json;charset=UTF-8");// 获取请求参数String name = req.getParameter("name");if (name == null || name.isEmpty()) {name = "World";}// 构造响应数据Map<String, String> responseData = new HashMap<>();responseData.put("message", "Hello, " + name + "!");// 将数据转换为 JSONString jsonResponse = new Gson().toJson(responseData);// 返回 JSON 响应resp.getWriter().write(jsonResponse);}
}

Spring MVC 示例(返回 JSON 数据)

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;import java.util.HashMap;
import java.util.Map;@RestController
public class JsonController {@GetMapping("/json")public Map<String, String> sayHello(@RequestParam(name = "name", required = false, defaultValue = "World") String name) {// 构造响应数据Map<String, String> response = new HashMap<>();response.put("message", "Hello, " + name + "!");return response;}
}

doGet()doPost()service() 的区别

特性service()doGet()doPost()
定位通用方法,用于处理所有 HTTP 请求类型。专门用于处理 HTTP GET 请求。专门用于处理 HTTP POST 请求。
调用方式由 Web 容器直接调用。service() 方法根据 HTTP 请求方法分发调用。service() 方法根据 HTTP 请求方法分发调用。
实现目的自动分发请求到对应的 doXxx() 方法。处理只读请求(如查询数据)。处理数据提交(如表单、文件上传)。
开发者重写很少被重写,通常由 Web 容器托管。常被重写以处理 GET 请求。常被重写以处理 POST 请求。
请求语义无特定语义,作为分发入口。遵循 HTTP GET 请求的语义(幂等)。遵循 HTTP POST 请求的语义(非幂等)。

六、总结

区别

  • Servlet 是 Java Web 开发的基础技术,提供了直接操作 HTTP 请求和响应的能力,适合小型项目或需要深入了解底层原理的场景。
  • Spring MVC 是一个基于 Servlet 的高级 Web 框架,提供了大量的自动化功能和开发便利性,适合中大型项目。

联系

  • Spring MVC 是建立在 Servlet 技术之上的框架,它通过 DispatcherServlet 实现请求的接收和分发。
  • Servlet 是 Spring MVC 的基础,但 Spring MVC 封装了许多底层细节,使开发更高效。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/66640.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

K-means算法在无监督学习中的应用

K-means算法在无监督学习中的应用 K-means算法是一种典型的无监督学习算法&#xff0c;广泛用于聚类分析。在无监督学习中&#xff0c;模型并不依赖于标签数据&#xff0c;而是根据输入数据的特征进行分组。K-means的目标是将数据集分成K个簇&#xff0c;使得同一簇内的数据点…

Linux 35.6 + JetPack v5.1.4之 pytorch升级

Linux 35.6 JetPack v5.1.4之 pytorch升级 1. 源由2. 升级步骤1&#xff1a;获取二进制版本步骤2&#xff1a;安装二进制版本步骤3&#xff1a;获取torchvision步骤4&#xff1a;安装torchvision步骤5&#xff1a;检查安装版本 3. 使用4. 补充4.1 torchvision版本问题4.2 支持…

ASP.NET Core 实现微服务 -- Polly 服务降级熔断

在我们实施微服务之后&#xff0c;服务间的调用变的异常频繁。多个服务之间可能是互相依赖的关系。某个服务出现故障或者是服务间的网络出现故障都会造成服务调用的失败&#xff0c;进而影响到某个业务服务处理失败。某一个服务调用失败轻则造成当前相关业务无法处理&#xff1…

Flink分区方式有哪些

Flink分区的方式决定了上游subtask的数据是如何流向下游subtask的,目前Flink提供了共8种分区算子,每个都对应着各自具体的分区器,可以见DataStream类里的方法shuffle、rebalance、rescale、keyBy、global、forward、broadcast、partitionCustom方法。以上方法除了keyBy返回的…

Spring——自动装配

假设一个场景&#xff1a; 一个人&#xff08;Person&#xff09;有一条狗&#xff08;Dog&#xff09;和一只猫(Cat)&#xff0c;狗和猫都会叫&#xff0c;狗叫是“汪汪”&#xff0c;猫叫是“喵喵”&#xff0c;同时人还有一个自己的名字。 将上述场景 抽象出三个实体类&…

TCP与DNS的报文分析

场景拓扑&#xff1a; 核心路由配置&#xff1a; 上&#xff08;DNS&#xff09;&#xff1a;10.1.1.1/24 下(WEB)&#xff1a;20.1.1.1/24 左&#xff08;client&#xff09;&#xff1a;192.168.0.1/24 右(PC3)&#xff1a;192.168.1.1/24Clint2配置&a…

PWR-STM32电源控制

一、原理 睡眠模式不响应其他操作&#xff0c;比如烧写程序&#xff0c;烧写时按住复位键松手即可下载&#xff0c;在禁用JTAG也可如此烧写程序。 对于低功耗模式可以通过RTC唤醒、外部中断唤醒、中断唤醒。 1、电源框图&#xff1a; VDDA主要负责模拟部分的供电、Vref和Vref-…

WebSocket 测试入门篇

Websocket 是一种用于 H5 浏览器的实时通讯协议&#xff0c;可以做到数据的实时推送&#xff0c;可适用于广泛的工作环境&#xff0c;例如客服系统、物联网数据传输系统&#xff0c; 基础介绍 我们平常接触最多的是 http 协议的接口&#xff0c;http 协议是请求与响应的模式&…

基于机器学习的故障诊断(入门向)

一、原始信号的特征提取 1.EMD经验模态分解的作用 信号分析&#xff1a;EMD可以将信号分解为多个IMFs&#xff0c;每个IMF代表信号中的一个特定频率和幅度调制的成分。这使得EMD能够提供对信号的时频特征进行分析的能力&#xff08;特征提取用到的&#xff09;。信号去噪&…

【算法刷题】leetcode hot 100 双指针

文章目录 283. 移动零11. 盛最多水的容器15. 三数之和42. 接雨水 283. 移动零 https://leetcode.cn/problems/move-zeroes/description/?envTypestudy-plan-v2&envIdtop-100-liked 解法一&#xff1a; 找到第一个等于0的下标&#xff0c;然后继续向右找到第一个不等于0的…

Flutter Xcode 16+ iOS 18.1 使用image_pickers无法弹出选择图片的视图问题

解决 Flutter Xcode 16 使用 image_pickers 无法弹出选择图片视图的问题 在开发 Flutter 应用时&#xff0c;图片选择功能是常见的需求之一。image_pickers 库因其便捷性和功能丰富性&#xff0c;成为了许多开发者的选择。然而&#xff0c;随着 Xcode 版本的不断更新&#xff…

高斯混合模型 (Gaussian Mixture Model, GMM) 算法详解与PyTorch实现

高斯混合模型 (Gaussian Mixture Model, GMM) 算法详解与PyTorch实现 目录 高斯混合模型 (Gaussian Mixture Model, GMM) 算法详解与PyTorch实现1. 高斯混合模型 (GMM) 算法概述1.1 高斯分布1.2 GMM的优势2. GMM的核心技术2.1 模型定义2.2 参数估计2.3 损失函数3. PyTorch实现G…

【蓝桥杯选拔赛真题60】C++寻宝石 第十四届蓝桥杯青少年创意编程大赛 算法思维 C++编程选拔赛真题解

目录 C++寻宝石 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 五、运行结果 六、考点分析 七、推荐资料 C++寻宝石 第十四届蓝桥杯青少年创意编程大赛C++选拔赛真题 一、题目要求 1、编程实现 有N(1<N<100)个盒子排成一排,每个盒子都放…

计算机组成原理(九):乘法器

乘法器原理 乘法器的工作原理可以用二进制乘法来说明。二进制乘法和十进制乘法类似&#xff0c;通过部分积的累加得到结果。 部分积的生成 在二进制乘法中&#xff0c;每一位的乘积是两个二进制数位的 与运算&#xff08;0 0 0&#xff0c;1 0 0&#xff0c;0 1 0&…

【汇编】x86汇编编程寄存器资源心中有数

1. CPU状态及控制寄存器 TR&#xff0c;GDTR&#xff0c;LDTRcr0-cr3EFLAGS 等等 2. 业务计算寄存器&#xff08;我起的名字&#xff09; 业务寄存器用于访问内存、参数传递、数据传递、计算。 段寄存器6个&#xff1a; cs&#xff0c;ds&#xff0c;es&#xff0c;ss&…

vue封装axios请求

在vue项目中我们发送请求一般是使用axios 我们可以封装axios来避免冗余代码 首先引入axios npm install axios创建环境配置文件 NODE_ENV development VITE_APP_TITLE dev VITE_APP_BASE_API /test VITE_SERVE "http://127.0.0.1"上面是创建dev配置文件 也可以…

Nginx入门笔记

Nginx入门笔记 一、Nginx基本概念二、代理1、正向代理2、反向代理 三、准备工作1、CentOS 7安装nginx&#xff08;1&#xff09;. 安装必要的依赖&#xff08;2&#xff09;下载nginx&#xff08;3&#xff09;编译安装&#xff08;4&#xff09;编译并安装 Nginx(5)启动nginx …

基于旋转框的目标检测算法简单实操

使用labelme工具&#xff0c;使用多边形方式进行标注。 pip install labelme 标注完成后只需要将标注的数据使用opencv的最小外接矩形框进行转化即可。 labelme标注的多边形格式数据转换成COCO旋转框格式&#xff0c;转换脚本代码如下&#xff1a; import os import json impo…

重塑视频创作的格局!ComfyUI-Mochi本地部署教程

一、介绍 mochi是近期Genmo公司开源的先进视频生成模型&#xff0c;具有高保真运动和强大的提示遵循性。此模型的发布极大的缩小了闭源和开源视频生成系统之间的差距。 目前&#xff0c;视频生成模型与现实之间存在巨大差距。其中最影响视频生成的两个关键功能也就是运动质量和…

el-table自定义按钮控制扩展expand

需求&#xff1a;自定义按钮实现表格扩展内容的展开和收起&#xff0c;实现如下&#xff1a; 将type“expand”的表格列的宽度设置为width"1"&#xff0c;让该操作列不展示出来&#xff0c;然后通过ref动态调用组件的内部方法toggleRowExpansion(row, row.expanded)控…