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 的核心思想是基于 请求-响应模型:
- 客户端(通常是浏览器)发送 HTTP 请求。
- Web 容器(如 Tomcat)将请求路由到 Servlet。
- Servlet 处理请求,执行逻辑,生成并返回 HTTP 响应。
3. 核心组件
HttpServletRequest
:表示客户端的请求对象,包含请求的所有信息(如请求参数、请求头等)。HttpServletResponse
:表示服务器的响应对象,包含响应的所有信息(如响应头、响应状态码、响应体等)。
4. Servlet 的生命周期
Servlet 的生命周期由 Web 容器管理,包含以下几个阶段:
- 初始化:
- Servlet 第一次被访问时,容器会加载 Servlet 类并调用
init()
方法完成初始化。
- Servlet 第一次被访问时,容器会加载 Servlet 类并调用
- 服务:
- 每次请求都会调用
service()
方法,根据请求的 HTTP 方法(GET、POST 等),调用对应的doGet()
或doPost()
方法。
- 每次请求都会调用
- 销毁:
- 在服务器关闭或卸载 Servlet 时,调用
destroy()
方法释放资源。
- 在服务器关闭或卸载 Servlet 时,调用
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 的核心组件:
- DispatcherServlet:
- 前端控制器,负责接收和分发所有 HTTP 请求。
- HandlerMapping:
- 请求映射器,将 URL 映射到具体的控制器方法。
- Controller:
- 业务处理器,负责执行具体的逻辑。
- ModelAndView:
- 数据模型和视图对象,用于封装业务数据和返回的视图信息。
- ViewResolver:
- 视图解析器,将逻辑视图名解析为物理视图(如 JSP、Thymeleaf 页面)。
- View:
- 负责生成最终的响应内容(HTML、JSON 等)。
4. 工作流程
Spring MVC的工作流程_spring mvc 的工作流程-CSDN博客
- 客户端发送请求。
- DispatcherServlet 接收请求并委托给 HandlerMapping 找到对应的 Controller 方法。
- Controller 方法处理请求,返回数据(Model)和视图(View)。
- ViewResolver 将逻辑视图名解析为物理视图。
- 将数据渲染到视图,生成响应并返回给客户端。
5. 示例代码
以下是一个简单的 Spring MVC 示例:
Controller 类:
@Controller
public class HelloController {@GetMapping("/hello")@ResponseBodypublic String sayHello(@RequestParam String name) {return "<h1>Hello, " + name + "!</h1>";}
}
三、Servlet 和 Spring MVC 的区别
对比维度 | Servlet | Spring 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 已被销毁!");} }
代码优化点
- 注解简化配置:
- 使用
@WebServlet
注解代替传统的web.xml
配置。- 默认参数处理:
- 如果用户未传递参数,返回默认的 "World"。
- 字符编码:
- 通过
resp.setContentType("text/html;charset=UTF-8")
设置字符编码,防止中文乱码。- 日志输出:
- 在
init()
和destroy()
方法中添加日志信息,便于调试。如何运行
- 将代码打包为
.war
文件,并部署到 Tomcat。- 访问 URL:
http://localhost:8080/hello?name=Tom
。- 返回结果:
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);} }
代码优化点
- 注解驱动开发:
- 使用
@Controller
和@GetMapping
注解处理请求,简化了配置。- 自动参数绑定:
- 使用
@RequestParam
自动从请求中提取参数,同时设置默认值。- 自动响应:
- 通过
@ResponseBody
将返回的字符串直接作为响应体,省去了手动处理HttpServletResponse
。- Spring Boot 快速启动:
- 使用 Spring Boot 自动化配置,无需单独部署到 Tomcat。
如何运行
- 将代码保存为一个 Spring Boot 应用。
- 运行主类
SpringMvcApplication
。- 访问 URL:
http://localhost:8080/hello?name=Tom
。- 返回结果:
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 封装了许多底层细节,使开发更高效。
相关文章:
Servlet 和 Spring MVC:区别与联系
前言 在 Java Web 开发中,Servlet 和 Spring MVC 是两个重要的技术。Servlet 是 Java Web 的基础组件,而 Spring MVC 是一个高级 Web 框架,建立在 Servlet 的基础之上,提供了强大的功能和易用性。这篇文章将从定义、原理、功能对…...

【期末复习】三、内存管理
1.物理内存管理 空闲内存管理方式主要分为:等长划分和不等长划分。 内存管理方式 单一连续分区 基本思想:一段时间内只有一个进程在内存。 特点:简单,内存利用率低, 有三种不同的布局: 固定分区 把内存空间分割成若干区域, 称为分区。 每个分区的大小可以相同也可…...

Microsoft Azure Cosmos DB:全球分布式、多模型数据库服务
目录 前言1. Azure Cosmos DB 简介1.1 什么是 Azure Cosmos DB?1.2 核心技术特点 2. 数据模型与 API 支持2.1 文档存储(Document Store)2.2 图数据库(Graph DBMS)2.3 键值存储(Key-Value Store)…...

【Docker】安装registry本地镜像库,开启Https功能
下载镜像 docker pull registry:2 需要启动https功能,就要生成服务端的自签名的证书和私钥,以及在docker客户端安装这个经过签名的证书。 第一步:生成公私钥信息,第二步,制作证书签名申请文件, 第三步&…...

JUC--线程池
线程池 七、线程池7.1线程池的概述7.2线程池的构建与参数ThreadPoolExecutor 的构造方法核心参数线程池的工作原理 Executors构造方法newFixedThreadPoolnewCachedThreadPoolnewSingleThreadExecutornewScheduledThreadPool(int corePoolSize) 为什么不推荐使用内置线程池&…...
后端Java开发:第十一天
第十一天:方法重载 - 理解与应用 今天我们继续深入 Java 的世界,讨论 Java 中的 方法重载(Method Overloading)。你可能会想,什么是方法重载?简单来说,方法重载允许你在一个类中定义多个同名方…...

基于 GEE 的长时间序列 Landsat 5 影像下载
目录 1 完整代码 2 运行结果 1 完整代码 var LT5 ee.ImageCollection("LANDSAT/LT05/C01/T1"),imageVisParam {"opacity":1,"bands":["B4","B3","B2"],"gamma":1},roi ee.FeatureCollection(&quo…...

Unity-Mirror网络框架从入门到精通之Attributes属性介绍
前言 在现代游戏开发中,网络功能日益成为提升游戏体验的关键组成部分。Mirror是一个用于Unity的开源网络框架,专为多人游戏开发设计。它使得开发者能够轻松实现网络连接、数据同步和游戏状态管理。本文将深入介绍Mirror的基本概念、如何与其他网络框架进…...

软考证书邮寄步骤
一、点击网址 https://www.ruankao.org.cn/ 复制上述网址,粘贴至浏览器中。点击 “报名入口” 。 二、点击入口 选择考试批次。点击你所在考试地点的入口并进入。 三、登录 输入手机号和密码。进行验证。 四、点击基本信息 点击右上角。进入 “基本信息” 。 五、…...

计算机网络 (29)网络地址转换NAT
前言 网络地址转换(Network Address Translation,NAT)是计算机网络中的一种重要协议,它主要用于将私有IP地址转换为公共IP地址,以实现内部网络与外部网络之间的通信。 一、基本概念 NAT是一种在局域网(LAN&…...

nlp培训重点-2
1. 贝叶斯公式 import math import jieba import re import os import json from collections import defaultdictjieba.initialize()""" 贝叶斯分类实践P(A|B) (P(A) * P(B|A)) / P(B) 事件A:文本属于类别x1。文本属于类别x的概率,记做…...

设计模式(1)——面向对象和面向过程,封装、继承和多态
文章目录 一、day11. 什么是面向对象2. 面向对象的三要素:继承、封装和多态2.1 封装**2.1.1 封装的概念****2.1.2 如何实现封装****2.1.3 封装的底层实现**2.1.4 为什么使用封装?(好处)**2.1.5 封装只有类能做吗?结构体…...
培训机构Day24
今天讲了一些javaee比较过时的技术,虽然已经过时,该学的还得学学。 知识点: http://localhost:8080/demo01/demo1?a1&b2&c3 pattern: /demo1 上下文路径:ContextPath,/demo01,不包含请求参数。 …...

1/7 C++
练习:要求在堆区连续申请5个int的大小空间用于存储5名学生的成绩,分别完成空间的申请、成绩的录入、升序排序、成绩输出函数,并在主程序中完成测试 要求使用new #include <iostream>using namespace std; double *addr_new() {double …...

C语言初阶习题【23】输出数组的前5项之和
1. 题目描述 求Snaaaaaaaaaaaaaaa的前5项之和,其中a是一个数字, 例如:222222222222222 2.思路 分析下,222222222222222,怎么把它每一项算出来 2 210222 22102222 2221022222 我们的多项式就是a a*102,…...

Android audio(1)-音频模块概述
Audio模块是Android系统的重要组成部分,在 Android 中负责音频路由,数据处理,音频控制,音频设备管理/切换。 下面的内容大多翻译自android官网,读者可跳过阅读后面的博客。 一、系统架构 下图说明了音频模块的组成,并指出各组成部分所涉及的相关源代码。所谓架构就是说模…...

园林与消防工程:选择正确工程项目管理软件的重要性
在园林与消防工程领域,选择正确的工程项目管理软件对于提高项目效率、优化资源配置以及确保项目质量至关重要。以下是对园林与消防工程中选择正确工程项目管理软件重要性的详细分析: 1.提升项目管理效率 实时监控与跟踪:工程项目管理软件能够…...
分布式环境下定时任务扫描时间段模板创建可预订时间段
🎯 本文详细介绍了场馆预定系统中时间段生成的实现方案。通过设计场馆表、时间段模板表和时间段表,系统能够根据场馆的提前预定天数生成未来可预定的时间段。为了确保任务执行的唯一性和高效性,系统采用分布式锁机制和定时任务,避…...

SQL刷题笔记——高级条件语句
目录 1题目:SQL149 根据指定记录是否存在输出不同情况 2 作答解析 3 知识点 3.1 count函数 3.2 内连接与左连接 1题目:SQL149 根据指定记录是否存在输出不同情况 2 作答解析 #正确答案 select uid, incomplete_cnt, incomplete_rate from (select …...
与 Oracle Dataguard 相关的进程及作用分析
与 Oracle Dataguard 相关的进程及作用分析 目录 与 Oracle Dataguard 相关的进程及作用分析与 Oracle Dataguard 相关的进程及作用分析一、主库的进程1、LGWR 进程2、ARCH进程3、LNS 进程 二、备库的进程1、RFS 进程2、ARCH3、MRP(Managed Recovery Process&#x…...

练习(含atoi的模拟实现,自定义类型等练习)
一、结构体大小的计算及位段 (结构体大小计算及位段 详解请看:自定义类型:结构体进阶-CSDN博客) 1.在32位系统环境,编译选项为4字节对齐,那么sizeof(A)和sizeof(B)是多少? #pragma pack(4)st…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...
Java入门学习详细版(一)
大家好,Java 学习是一个系统学习的过程,核心原则就是“理论 实践 坚持”,并且需循序渐进,不可过于着急,本篇文章推出的这份详细入门学习资料将带大家从零基础开始,逐步掌握 Java 的核心概念和编程技能。 …...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!
简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求,并检查收到的响应。它以以下模式之一…...

Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...

C++:多态机制详解
目录 一. 多态的概念 1.静态多态(编译时多态) 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1).协变 2).析构函数的重写 5.override 和 final关键字 1&#…...

打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用
一、方案背景 在现代生产与生活场景中,如工厂高危作业区、医院手术室、公共场景等,人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式,存在效率低、覆盖面不足、判断主观性强等问题,难以满足对人员打手机行为精…...

STM32---外部32.768K晶振(LSE)无法起振问题
晶振是否起振主要就检查两个1、晶振与MCU是否兼容;2、晶振的负载电容是否匹配 目录 一、判断晶振与MCU是否兼容 二、判断负载电容是否匹配 1. 晶振负载电容(CL)与匹配电容(CL1、CL2)的关系 2. 如何选择 CL1 和 CL…...

Linux中《基础IO》详细介绍
目录 理解"文件"狭义理解广义理解文件操作的归类认知系统角度文件类别 回顾C文件接口打开文件写文件读文件稍作修改,实现简单cat命令 输出信息到显示器,你有哪些方法stdin & stdout & stderr打开文件的方式 系统⽂件I/O⼀种传递标志位…...