前言
在 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 { @override protected 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. 工作流程
- 客户端发送请求。
- dispatcherservlet 接收请求并委托给 handlermapping 找到对应的 controller 方法。
- controller 方法处理请求,返回数据(model)和视图(view)。
- viewresolver 将逻辑视图名解析为物理视图。
- 将数据渲染到视图,生成响应并返回给客户端。
5. 示例代码
以下是一个简单的 spring mvc 示例:
controller 类:
@controller public class hellocontroller { @getmapping("/hello") @responsebody public 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(只执行一次) @override public void init() throws servletexception { super.init(); system.out.println("servlet 初始化完成!"); } // 处理 get 请求 @override protected 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(只执行一次,用于释放资源) @override public 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") @responsebody public 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 { @override protected void doget(httpservletrequest req, httpservletresponse resp) throws servletexception, ioexception { // 设置响应类型为 json resp.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 + "!"); // 将数据转换为 json string 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 封装了许多底层细节,使开发更高效。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论