前言
在 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 封装了许多底层细节,使开发更高效。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论