快速了解 servlet(SpringMVC 的底层)
Servlet 是 Java EE(现 Jakarta EE)中用于处理 Web 请求的核心组件。它在 Web 应用程序的服务器端运行,负责接收和处理客户端(如浏览器)的请求,并生成响应。
尽管现代Web开发更多采用SpringMVC等框架,但Servlet作为基础仍然重要,Spring MVC 的底层核心是基于 Servlet API 的,它本质上是对 Java EE Servlet 规范的进一步封装和扩展。通过这种封装,Spring MVC 提供了一个更高级别的、易于开发的 Web 框架。Spring MVC 的控制器方法基于注解的形式,简化了 Web 开发流程,但底层还是依赖于 Servlet 来处理 HTTP 请求。
下面是关于 Servlet 的详细介绍:
1. Servlet 的定义和作用
- 定义: Servlet 是一个实现了
javax.servlet.Servlet
接口的 Java 类,或者更常见的是继承HttpServlet
类。它用于处理客户端的请求并生成响应。 - 作用: 通过 Servlet,可以在服务器端动态生成内容(如 HTML、JSON、XML),并与客户端进行交互。
2. Servlet 的生命周期
Servlet 的生命周期包括以下几个阶段:
- 加载和实例化: 当 Servlet 容器启动时,它会加载 Servlet 类,并创建 Servlet 的实例。
- 初始化: 容器调用 Servlet 的
init()
方法进行初始化。此方法在 Servlet 实例创建后、处理请求之前被调用。可以在此方法中进行一次性的设置,如数据库连接的建立。 - 请求处理: 每当有请求到达 Servlet 时,容器会调用 Servlet 的
service()
方法来处理请求。service()
方法根据请求的类型(GET、POST 等)调用相应的doGet()
、doPost()
等方法。 - 销毁: 当 Servlet 容器卸载 Servlet 或容器关闭时,调用 Servlet 的
destroy()
方法。这时可以释放资源,如关闭数据库连接。
3. Servlet 接口和 HttpServlet 类
Servlet
接口:Servlet
接口是所有 Servlet 的基接口,定义了一些核心方法,如init()
、service()
和destroy()
。HttpServlet
类:HttpServlet
是Servlet
接口的实现类,提供了对 HTTP 请求的支持。它将请求类型分为 GET、POST、PUT、DELETE 等,并提供了对应的方法:doGet()
、doPost()
、doPut()
、doDelete()
等。
4. Servlet 方法
init(ServletConfig config)
: 初始化 Servlet,ServletConfig
对象包含 Servlet 的配置参数。service(ServletRequest req, ServletResponse res)
: 处理请求,并生成响应。通常由容器调用。destroy()
: 释放 Servlet 使用的资源。doGet(HttpServletRequest req, HttpServletResponse res)
: 处理 GET 请求。doPost(HttpServletRequest req, HttpServletResponse res)
: 处理 POST 请求。
5. Servlet 请求和响应
HttpServletRequest
: 提供了对客户端请求信息的访问,包括请求参数、头信息、请求方法等。HttpServletResponse
: 用于发送响应到客户端,包括设置响应内容类型、状态码、输出响应内容等。
HttpServletRequest
和 HttpServletResponse
是 Java Servlet API 中的两个核心接口,它们分别用于表示客户端发送给服务器的 HTTP 请求以及服务器发送给客户端的 HTTP 响应。在 Servlet 开发中,这两个接口被广泛用于处理 Web 应用中的请求和响应。
下面是对这两个接口的详细讲解,包括常用的方法和示例代码:
1. HttpServletRequest
详解
HttpServletRequest
接口代表客户端发送的 HTTP 请求,包含了与请求相关的所有信息,比如请求头、请求参数、请求路径、请求方法等。
常用方法
(1) 获取请求方法
String method = req.getMethod();
- 作用: 返回请求的 HTTP 方法(如
GET
、POST
、PUT
、DELETE
等)。
(2) 获取请求参数
String paramValue = req.getParameter("paramName");
- 作用: 用于获取客户端通过 URL、表单提交等方式发送的请求参数。
- 注意: 如果参数名在请求中不存在,返回
null
。
(3) 获取请求路径
String requestURI = req.getRequestURI();
- 作用: 返回请求的资源路径,通常用于确定客户端请求了哪个资源。例如
/myapp/index.jsp
。
(4) 获取请求头信息
String userAgent = req.getHeader("User-Agent");
- 作用: 用于获取请求头中的某些信息,比如客户端的浏览器信息、Cookies、Referer 等。
(5) 获取客户端 IP 地址
String clientIp = req.getRemoteAddr();
- 作用: 返回客户端的 IP 地址,通常用于记录或安全检查。
(6) 获取请求体内容
- 如果客户端发送的是 POST 请求,并且包含了请求体(如表单数据或 JSON),可以通过以下方法读取请求体内容:
BufferedReader reader = req.getReader();
String line;
while ((line = reader.readLine()) != null) {// 读取请求体中的内容
}
(7) 获取请求的上下文路径
String contextPath = req.getContextPath();
- 作用: 返回 Web 应用的上下文路径,在一个应用中通常是它的根路径。比如
/myapp
。
(8) 获取请求的 URL 参数
String queryString = req.getQueryString();
- 作用: 返回 URL 中的查询字符串部分。例如对于 URL
/myapp/resource?id=123&name=Tom
,返回id=123&name=Tom
。
示例代码
@WebServlet("/myservlet")
public class MyServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 获取请求方法String method = req.getMethod();// 获取请求参数String param = req.getParameter("name");// 获取请求路径String requestURI = req.getRequestURI();// 获取客户端IPString clientIp = req.getRemoteAddr();// 处理逻辑...// 设置响应resp.getWriter().write("Request processed");}
}
2. HttpServletResponse
详解
HttpServletResponse
接口代表服务器发送给客户端的 HTTP 响应,用于生成响应数据并发送给客户端。你可以设置响应状态码、响应头、响应体等信息。
常用方法
(1) 设置响应状态码
resp.setStatus(HttpServletResponse.SC_OK);
- 作用: 设置 HTTP 响应的状态码。常见状态码包括:
SC_OK
(200):请求成功。SC_NOT_FOUND
(404):资源未找到。SC_INTERNAL_SERVER_ERROR
(500):服务器内部错误。
(2) 设置响应头
resp.setHeader("Content-Type", "text/html;charset=UTF-8");
- 作用: 设置 HTTP 响应头。常用于指定响应的内容类型、缓存策略、重定向等。
(3) 发送重定向
resp.sendRedirect("http://www.example.com");
- 作用: 通过这个方法可以让服务器将客户端重定向到另一个 URL。
(4) 设置响应内容类型
resp.setContentType("text/html;charset=UTF-8");
- 作用: 设置响应的内容类型,告诉客户端如何解释响应的数据格式。常见的内容类型包括:
text/html
:HTML 文本。application/json
:JSON 数据。image/png
:PNG 图片。
(5) 设置响应体内容
- 可以通过
PrintWriter
向客户端输出响应内容:
PrintWriter out = resp.getWriter();
out.println("<html><body>Hello, World!</body></html>");
(6) 设置响应的 Cookie
Cookie cookie = new Cookie("username", "Tom");
cookie.setMaxAge(3600); // 1小时
resp.addCookie(cookie);
- 作用: 用于向客户端设置 Cookie,客户端会存储这些 Cookie 并在下次请求时发送给服务器。
示例代码
@WebServlet("/myresponse")
public class MyServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 设置响应的内容类型为 HTMLresp.setContentType("text/html;charset=UTF-8");// 设置状态码resp.setStatus(HttpServletResponse.SC_OK);// 输出响应内容PrintWriter out = resp.getWriter();out.println("<html><body>");out.println("<h1>Hello, this is the response from the server!</h1>");out.println("</body></html>");}
}
3. HttpServletRequest
和 HttpServletResponse
的关系
-
请求处理: 当客户端向服务器发送请求时,服务器会生成一个
HttpServletRequest
对象,封装该请求的所有信息(如路径、参数、请求头等),并将其传递给 Servlet 的doGet()
、doPost()
等方法。 -
响应生成:
HttpServletResponse
对象用于处理服务器要返回给客户端的响应信息。你可以通过它设置响应的状态码、响应头以及返回给客户端的数据内容。 -
示例场景:
- 客户端通过浏览器发送一个 GET 请求给服务器,服务器生成一个
HttpServletRequest
对象。 - 服务器处理请求,生成一个 HTML 页面,使用
HttpServletResponse
将该页面返回给客户端。
- 客户端通过浏览器发送一个 GET 请求给服务器,服务器生成一个
6. 配置 Servlet
web.xml
配置: 在WEB-INF/web.xml
文件中配置 Servlet 的映射。例如:<servlet><servlet-name>MyServlet</servlet-name><servlet-class>com.example.MyServlet</servlet-class> </servlet> <servlet-mapping><servlet-name>MyServlet</servlet-name><url-pattern>/myservlet</url-pattern> </servlet-mapping>
- 注解配置: 从 Servlet 3.0 开始,支持使用注解进行配置。例如:
@WebServlet("/myservlet") public class MyServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 处理 GET 请求} }
7. Cookie 详解
Cookie 是客户端与服务器之间用于存储少量数据的机制。它允许服务器在客户端(通常是浏览器)上存储数据,以便在后续请求中可以再次读取。Cookie 是在 HTTP 请求和响应中传递的,并且可以跨多个请求共享。它们常用于实现会话管理、用户追踪以及保存用户偏好等功能。
1. Cookie 的基本结构
一个 HTTP Cookie 的基本结构如下:
- 键值对:
name=value
,键值对是 Cookie 的核心,存储数据内容。 - 属性:Cookie 还可以包含其他属性,比如
expires
(过期时间)、path
(路径)、domain
(域名)等,控制 Cookie 的有效期和范围。
一个典型的 Cookie 示例:
Set-Cookie: username=JohnDoe; Expires=Wed, 09 Jun 2024 10:18:14 GMT; Path=/
这个 Cookie 在客户端存储了用户名,并指定了过期时间和有效路径。
2. Cookie 的工作原理
-
服务器设置 Cookie:当客户端第一次访问服务器时,服务器可以通过 HTTP 响应头
Set-Cookie
设置 Cookie。客户端(浏览器)接收到该响应后,会将 Cookie 存储。 -
客户端发送 Cookie:在后续的请求中,客户端会将之前存储的 Cookie 自动附加到请求的 HTTP 头部,发送给服务器。这使得服务器可以识别同一个客户端的不同请求。
-
服务器读取 Cookie:服务器可以通过
HttpServletRequest
获取客户端发送的 Cookie 信息,进行处理或验证。
3. Cookie 的常用属性
- name=value:这是 Cookie 的核心部分,表示键值对,例如
username=JohnDoe
。 - expires:表示 Cookie 的过期时间,使用 GMT 格式。例如:
Expires=Wed, 09 Jun 2024 10:18:14 GMT
。 - max-age:指定 Cookie 的存活时间(以秒为单位)。如
Max-Age=3600
,表示 Cookie 在 3600 秒(1 小时)后过期。 - domain:指定 Cookie 的适用域名,例如
Domain=example.com
,这样该域下的所有子域都可以访问此 Cookie。 - path:限制 Cookie 的适用路径。
Path=/
表示 Cookie 对整个网站有效,Path=/app
表示仅对/app
路径及其子路径有效。 - secure:指定该 Cookie 只能通过 HTTPS 连接传输,保证数据的传输安全。
- HttpOnly:指定 Cookie 只能在 HTTP 请求中传递,不能通过 JavaScript 访问,增强安全性,防止 XSS 攻击。
4. Cookie 的生命周期
-
会话 Cookie(Session Cookie):默认情况下,Cookie 是临时的,生命周期与浏览器会话一致,当浏览器关闭时,Cookie 就会被删除。这类 Cookie 不设置
Expires
或Max-Age
。 -
持久 Cookie(Persistent Cookie):通过设置
Expires
或Max-Age
属性,Cookie 可以在浏览器关闭后继续存在,直到指定的时间过期。
5. Java 中的 Cookie 操作
在 Java Servlet 中,我们通过 javax.servlet.http.Cookie
类来创建和管理 Cookie。以下是常见的操作:
5.1 创建和设置 Cookie
// 创建 Cookie 对象
Cookie cookie = new Cookie("username", "JohnDoe");// 设置 Cookie 过期时间(以秒为单位),例如 1 小时
cookie.setMaxAge(3600);// 设置 Cookie 的适用路径
cookie.setPath("/");// 设置 Cookie 的安全性
cookie.setHttpOnly(true);// 将 Cookie 添加到响应中,发送给客户端
resp.addCookie(cookie);
5.2 读取 Cookie
// 从请求中获取所有的 Cookie
Cookie[] cookies = req.getCookies();if (cookies != null) {for (Cookie cookie : cookies) {if ("username".equals(cookie.getName())) {String username = cookie.getValue();System.out.println("Username: " + username);}}
}
5.3 删除 Cookie
删除 Cookie 的方法是设置它的过期时间为 0。
Cookie cookie = new Cookie("username", "");
cookie.setMaxAge(0); // 设置过期时间为 0
cookie.setPath("/"); // 需要设置相同的路径才能删除
resp.addCookie(cookie);
6. 常见的使用场景
-
会话管理:Cookie 常用于会话管理,例如用户登录时,服务器可以生成一个唯一的会话 ID(Session ID),并将其存储在客户端的 Cookie 中。在后续的请求中,客户端会携带这个会话 ID,服务器就可以识别出当前的用户。
-
保存用户偏好:Cookie 也常用于保存用户的偏好设置,例如语言选择、主题颜色等。下次用户访问网站时,Cookie 可以提供这些信息,服务器据此进行个性化展示。
-
跟踪用户行为:一些广告公司和分析工具使用 Cookie 跟踪用户在不同网站上的行为,以便投放个性化广告。
8. Session 详解
Session(会话)是在客户端与服务器之间保持的会话状态管理机制,用于存储用户在浏览器与服务器进行交互期间的状态信息。Session 通常与 Cookie 配合使用,但它比 Cookie 更加安全,因为会话数据通常存储在服务器端,而客户端只是保存一个会话 ID。
1. Session 的基本概念
Session 是服务器为每个用户创建的独立会话,用来保存该用户的相关信息。在用户访问网站时,服务器会生成一个唯一的会话标识(Session ID),并将其发送给客户端。客户端随后会在每次请求时通过 Cookie 或 URL 携带该 Session ID,服务器可以根据这个 ID 找到相应的会话数据,进而为用户提供个性化的服务。
Session 与 Cookie 的区别:
- 存储位置:Session 数据存储在服务器端,而 Cookie 数据存储在客户端(浏览器)。
- 安全性:Session 更安全,因为数据不存储在客户端,防止被用户篡改。而 Cookie 的数据暴露在客户端,容易被恶意修改。
- 大小限制:Session 没有大小限制,而 Cookie 每个键值对的大小一般不超过 4KB。
- 生命周期:Session 一般在会话结束或超时后失效,Cookie 可以设置长期有效。
2. Session 的工作原理
-
客户端发起请求:用户第一次访问服务器时,服务器根据请求创建一个新的会话(Session),并生成一个唯一的 Session ID。
-
服务器生成 Session ID:服务器将生成的 Session ID 返回给客户端,通常以 Cookie 的形式发送给浏览器,存储在
Set-Cookie
头部字段中。 -
客户端保存 Session ID:浏览器会保存这个 Session ID,并在后续请求中将其包含在 HTTP 请求的 Cookie 中,发送给服务器。
-
服务器识别 Session ID:每次客户端请求时,服务器通过 Session ID 来查找并恢复该用户的会话状态。服务器会根据 Session ID 来访问保存在服务器端的会话数据。
-
会话结束:会话可以在浏览器关闭时、用户登出时、或服务器设置的超时时间到达后自动结束。
3. Session 的生命周期
-
创建:当客户端第一次访问服务器时,服务器会为该客户端创建一个新的 Session 对象,并生成一个唯一的 Session ID。这个 ID 通常通过
JSESSIONID
Cookie 存储在客户端。 -
存活:Session 默认的存活时间与用户的浏览器会话一致,用户关闭浏览器后,Session 失效。不过,也可以通过配置来改变其存活时间。
-
销毁:
- 服务器超时:如果用户长时间未访问服务器,Session 会自动超时并销毁。这个超时时间可以在服务器配置中设置,例如 Tomcat 中的
web.xml
。 - 用户登出:服务器可以在用户登出时手动销毁该用户的 Session。
- 浏览器关闭:会话结束通常伴随着浏览器关闭,虽然这不是严格的规则。
- 服务器超时:如果用户长时间未访问服务器,Session 会自动超时并销毁。这个超时时间可以在服务器配置中设置,例如 Tomcat 中的
4. Java 中的 Session 操作
在 Java Servlet 中,使用 HttpSession
接口来操作会话数据。
4.1 获取 HttpSession
每当用户发送请求时,Servlet 可以通过 HttpServletRequest
对象获取当前用户的 Session:
HttpSession session = request.getSession();
request.getSession()
:如果当前会话不存在,会创建一个新的会话对象。request.getSession(false)
:如果当前会话不存在,返回null
。
4.2 设置 Session 数据
可以通过 HttpSession
的 setAttribute
方法将数据存储到会话中:
HttpSession session = request.getSession();
session.setAttribute("username", "JohnDoe"); // 将用户名存储到 Session
4.3 获取 Session 数据
使用 getAttribute
方法获取会话中存储的数据:
HttpSession session = request.getSession();
String username = (String) session.getAttribute("username"); // 获取存储的用户名
4.4 删除 Session 数据
使用 removeAttribute
方法可以移除会话中的某个属性:
HttpSession session = request.getSession();
session.removeAttribute("username"); // 移除存储的用户名
4.5 设置 Session 失效时间
可以通过 setMaxInactiveInterval
方法设置 Session 的超时时间(单位:秒):
HttpSession session = request.getSession();
session.setMaxInactiveInterval(1800); // 设置会话30分钟后失效
4.6 手动销毁 Session
通过 invalidate
方法可以手动销毁会话:
HttpSession session = request.getSession();
session.invalidate(); // 销毁会话
5. Session 作用域
Session 是 Servlet/JSP 中的一种作用域,用于存储跨多个请求的数据。与其他作用域相比,Session 的作用域更大,因为它在整个用户会话期间都是有效的。
- Request 作用域:仅在一个 HTTP 请求中有效。
- Session 作用域:在整个用户会话期间有效,跨越多个 HTTP 请求。
- Application 作用域:在整个 Web 应用程序的生命周期中有效,对所有用户共享。
- Page 作用域:仅在当前 JSP 页面的范围内有效。
6. Session 和 Cookie 的配合使用
Session 的工作依赖于 Cookie 来保存 Session ID。浏览器会将服务器返回的 JSESSIONID
Cookie 保存下来,后续每次请求都会自动附带这个 Cookie,从而服务器可以根据这个 ID 识别出用户的会话。
如果客户端禁用了 Cookie,Session 仍然可以通过 URL 重写机制传递 Session ID。即在 URL 中添加 ;jsessionid=xxxxxx
来传递会话 ID,但这并不常用,因为暴露在 URL 中的会话 ID 可能带来安全问题。
7. Session 的常见使用场景
-
用户登录认证:在用户登录成功后,将用户的信息(例如用户 ID 或用户名)存储在 Session 中,这样用户在访问后续页面时,服务器可以通过 Session 识别出当前用户的身份。
-
购物车管理:在线商城中,Session 常用于保存用户的购物车信息,即使用户在多个页面间跳转,购物车的内容也能保持不变。
-
个性化设置:通过 Session 保存用户的个性化设置(如语言、主题等),使得用户在多个页面中保持一致的体验。
8. Session 的优缺点
优点:
- 服务器端存储:数据存储在服务器上,更安全,用户无法轻易篡改。
- 状态保持:在多个请求之间保持用户状态,方便管理用户信息和操作。
- 跨页面共享:Session 可以跨多个页面共享数据,适合用来存储较大的、敏感的或需要跨页面共享的信息。
缺点:
- 服务器开销:Session 数据存储在服务器上,随着用户量增大,服务器的内存消耗也会增加。
- 依赖 Cookie 或 URL 重写:Session 通常依赖于 Cookie,如果客户端禁用了 Cookie,就需要使用其他机制传递 Session ID。
- 失效控制:需要合理设置 Session 的失效时间,避免用户会话超时问题或服务器负载增加。
9. 作用域
1. Request 作用域
- 作用范围:Request 作用域的数据仅在一次请求内有效,通常用于当前请求过程中多个组件(如 Servlet 或 JSP)之间的数据共享。
- 生命周期:数据在请求开始时创建,在请求结束时销毁。
- 典型场景:从一个 Servlet 转发到另一个 Servlet 或 JSP,并传递数据。
常用方法:
setAttribute(String name, Object value)
:将数据存入 request 作用域。getAttribute(String name)
:从 request 作用域获取数据。removeAttribute(String name)
:从 request 作用域移除数据。
示例:
@WebServlet("/requestScopeExample")
public class RequestScopeExample extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 将数据存入 Request 作用域req.setAttribute("message", "Hello from Request Scope!");// 转发到 JSP 进行展示req.getRequestDispatcher("/display.jsp").forward(req, resp);}
}
2. Session 作用域
- 作用范围:Session 作用域的数据对同一用户的多个请求有效,直到用户的 session 过期或被销毁。
- 生命周期:session 在第一次访问服务器时创建,并在用户不活动一段时间后(默认 30 分钟)或手动销毁时结束。
- 典型场景:用户登录后,保持用户登录状态或存储用户信息。
常用方法:
getSession()
:获取当前用户的 session(如果没有,则创建一个新的 session)。getSession(boolean create)
:获取当前 session,如果create
为false
则不会创建新 session。setAttribute(String name, Object value)
:将数据存入 session 作用域。getAttribute(String name)
:从 session 作用域获取数据。removeAttribute(String name)
:从 session 作用域移除数据。
示例:
@WebServlet("/sessionScopeExample")
public class SessionScopeExample extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 获取 session 对象,如果没有则创建新的HttpSession session = req.getSession();// 设置 session 作用域中的属性session.setAttribute("username", "JohnDoe");// 跳转到页面展示 session 中的数据resp.sendRedirect("displaySession.jsp");}
}
3. 不同作用域之间的区别
作用域 | 范围 | 生命周期 | 典型使用场景 |
---|---|---|---|
Request | 当前请求 | 请求开始到请求结束 | 转发数据给另一个 Servlet 或 JSP |
Session | 当前用户的所有请求 | 用户会话期间 | 保存登录信息或用户数据 |
10. ServletContext
ServletContext
是为整个 Web 应用程序提供的共享空间,所有的 Servlet 和 JSP 都可以通过它来共享数据。ServletContext
是由 Servlet 容器(如 Tomcat)创建的,在 Web 应用启动时初始化,并在 Web 应用程序停止时销毁。
1. 如何获取 ServletContext
对象
可以通过以下几种方式来获取 ServletContext
:
-
通过
HttpServlet
的getServletContext()
方法:ServletContext context = getServletContext();
-
通过
HttpServletRequest
的getServletContext()
方法:ServletContext context = req.getServletContext();
-
在
web.xml
中定义的ServletContextListener
中:
在contextInitialized()
方法中可以获取ServletContext
。public class MyContextListener implements ServletContextListener {@Overridepublic void contextInitialized(ServletContextEvent sce) {ServletContext context = sce.getServletContext();} }
2. ServletContext
的主要功能
2.1 共享数据
ServletContext
允许在整个应用程序范围内共享数据。它提供了 setAttribute()
和 getAttribute()
方法,用于存储和检索共享的数据。
-
存储数据:
ServletContext context = getServletContext(); context.setAttribute("myData", "Some shared data");
-
检索数据:
String data = (String) getServletContext().getAttribute("myData");
-
删除数据:
getServletContext().removeAttribute("myData");
2.2 访问初始化参数
可以通过 ServletContext
获取在 web.xml
中配置的全局初始化参数(<context-param>
),这些参数在整个应用中是共享的。
-
在
web.xml
中配置初始化参数:<context-param><param-name>appName</param-name><param-value>My Application</param-value> </context-param>
-
通过
ServletContext
获取参数:String appName = getServletContext().getInitParameter("appName");
2.3 获取 Web 应用的上下文路径
可以通过 ServletContext
来获取 Web 应用程序的上下文路径(即应用在服务器上的根路径):
String contextPath = getServletContext().getContextPath();
2.4 访问 Web 应用的资源
ServletContext
可以用来访问 Web 应用程序中的静态资源(如 HTML 文件、CSS 文件等)。常见的方法包括:
-
getResource()
和getResourceAsStream()
:用于获取应用内的资源的 URL 或输入流。InputStream is = getServletContext().getResourceAsStream("/WEB-INF/config.properties");
-
获取应用部署目录的实际路径:
String realPath = getServletContext().getRealPath("/index.html");
2.5 记录日志
ServletContext
提供了一个简便的日志记录功能,可以通过 log()
方法记录应用程序运行时的日志信息。
getServletContext().log("This is a log message");
2.6 管理 Servlet 生命周期
通过 ServletContext
,可以获取到特定的 Servlet
实例,也可以获取 Servlet 的配置信息(不推荐直接使用这种方式,通常使用注解或配置文件)。
3. 作用范围
ServletContext
的作用范围是整个 Web 应用程序,也就是说在同一个 Web 应用中的所有 Servlet、JSP 和过滤器都共享同一个 ServletContext
对象。它的生命周期和 Web 应用一致,当应用程序启动时,ServletContext
对象创建;当应用程序停止时,ServletContext
对象销毁。
对比
1. Servlet 与 Spring Boot Controller 的相似点
- 注解驱动开发: 都使用注解来定义请求处理的逻辑。通过注解可以方便地将特定路径映射到某个方法或类上。
- 请求处理: 无论是 Servlet 还是 Spring Boot,核心目标都是处理客户端(浏览器、HTTP 客户端等)的请求,并生成响应。
- 路径映射: 都提供了路径映射的方式,将客户端的 HTTP 请求映射到特定的处理逻辑上。
2. Servlet 注解和 Spring Boot 注解对比
特性 | Servlet(Java EE/Jakarta EE) | Spring Boot(Spring MVC) |
---|---|---|
类注解 | @WebServlet("/path") | @RestController 或 @Controller |
请求处理方法 | doGet() 、doPost() 等 | @GetMapping("/path") 、@PostMapping("/path") 等 |
请求参数 | HttpServletRequest 、HttpServletResponse | 自动注入参数,例如 @RequestParam 、@PathVariable |
返回数据类型 | 通过 PrintWriter 输出响应数据 | 直接返回对象(如 String 、JSON ),自动序列化响应 |
依赖注入 | 手动管理对象和依赖 | 使用 Spring 的 IoC 容器自动进行依赖注入 |
配置方式 | web.xml 或注解 | 基于注解和 Spring Boot 自动配置,无需显式配置文件 |
请求类型处理 | 通过 service() 、doGet() 、doPost() | 通过 @GetMapping 、@PostMapping 等注解区分请求类型 |
3. Servlet 和 Spring Boot 的区别
-
开发复杂度:
- Servlet: 使用 Servlet 时,开发者需要手动处理请求和响应的很多细节,比如处理
HttpServletRequest
和HttpServletResponse
对象、手动解析请求参数、处理响应等。 - Spring Boot: Spring Boot 和 Spring MVC 在 Servlet 之上进行了封装和抽象,使得开发更简单。例如,你可以直接在方法上通过注解来处理 GET、POST 请求,Spring 会自动注入请求参数,并处理返回数据的序列化等工作。
- Servlet: 使用 Servlet 时,开发者需要手动处理请求和响应的很多细节,比如处理
-
请求处理方法:
- Servlet: 你通常在
doGet()
、doPost()
等方法中处理不同的 HTTP 请求。每次处理请求时,必须显式地操作HttpServletRequest
和HttpServletResponse
对象。 - Spring Boot: Spring MVC 提供了
@GetMapping
、@PostMapping
、@RequestMapping
等注解,可以直接将 HTTP 请求映射到方法中,并通过注解自动注入请求参数,例如通过@RequestParam
或@PathVariable
获取 URL 中的参数。
- Servlet: 你通常在
-
返回类型:
- Servlet: 开发者必须手动处理响应的输出,通常需要通过
PrintWriter
将内容输出到客户端。生成 JSON 或 XML 响应需要额外的序列化代码。 - Spring Boot: Spring MVC 会自动将 Java 对象转换为 JSON、XML 或其他格式,并直接返回给客户端。你只需返回一个对象,Spring 会自动处理序列化工作。例如:
@RestController public class MyController {@GetMapping("/hello")public String hello() {return "Hello, World!";} }
- Servlet: 开发者必须手动处理响应的输出,通常需要通过
-
依赖注入:
- Servlet: Servlet 本身并不提供依赖注入的功能,开发者需要手动创建和管理对象。如果使用依赖注入,通常需要配合 Spring 或其他 IoC 容器。
- Spring Boot: Spring Boot 使用 Spring 框架的 IoC 容器,支持强大的依赖注入功能。你可以使用
@Autowired
、@Service
、@Repository
等注解来简化依赖管理。
4. Servlet 和 Spring Boot 的联系
Spring Boot 是建立在 Servlet 之上的,Spring MVC 是 Spring 框架中的 Web 组件,它本质上仍然依赖于 Servlet 容器来处理 HTTP 请求。因此,在 Spring Boot 应用中,底层仍然是 Servlet,但 Spring 对其进行了高级封装,使开发者可以通过更高层次的注解和方法来处理 Web 请求,而不需要关心 Servlet 的底层细节。
- Spring Boot 底层依赖 Servlet: Spring Boot 内部仍然使用 Servlet 处理 HTTP 请求,比如
DispatcherServlet
是 Spring MVC 的核心类,用于将请求分发给控制器处理。 - 简化的开发体验: Spring Boot 封装了 Servlet 的许多低级细节,通过注解简化了 Web 开发的过程,并且提供了更多的功能,比如自动配置、数据绑定、异常处理等。
总结
- Servlet 是 Java EE/Jakarta EE 的核心技术,用于处理 Web 请求,开发者需要手动处理很多细节。
- Spring Boot 基于 Servlet 之上,通过注解和封装提供了更高层次的 Web 开发体验,简化了请求处理、依赖管理和数据绑定。
- 这两者在设计上有相似之处(比如注解驱动开发),但 Spring Boot 更注重开发的简便性和功能的完整性。
相关文章:

快速了解 servlet(SpringMVC 的底层)
Servlet 是 Java EE(现 Jakarta EE)中用于处理 Web 请求的核心组件。它在 Web 应用程序的服务器端运行,负责接收和处理客户端(如浏览器)的请求,并生成响应。 尽管现代Web开发更多采用SpringMVC等框架&…...

QT中tr的作用是什么
在Qt框架中,tr() 函数是一个非常重要的宏,它用于国际化和本地化(i18n和l10n)支持。tr() 函数使得Qt应用程序能够根据不同的语言环境(locale)显示相应的翻译文本,从而支持多种语言。 具体来说&a…...

OpenCV结构分析与形状描述符(7)计算轮廓的面积的函数contourArea()的使用
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 计算轮廓的面积。 该函数计算轮廓的面积。与 moments 类似,面积是使用格林公式计算的。因此,返回的面积与你使用 drawCo…...

内网环境使用Docker部署Qwen2模型-vLLM篇
在此之前,我们已成功利用Docker与Ollama框架,在内网环境中部署了Qwen2模型。下面我们再来看一下使用Docker与vLLM框架部署Qwen2模型。 准备vLLM镜像 在一台具备网络环境的机器上执行以下命令,拉取vLLM的镜像: # 官方镜像 docke…...

Rust的常数、作用域与所有权
【图书介绍】《Rust编程与项目实战》-CSDN博客 《Rust编程与项目实战》(朱文伟,李建英)【摘要 书评 试读】- 京东图书 (jd.com) Rust到底值不值得学,之一 -CSDN博客 Rust到底值不值得学,之二-CSDN博客 Rust的数据类型-CSDN博客 3.7 常…...

Spring 源码解读:解决循环依赖的三种方式
引言 在复杂的应用开发中,循环依赖是一个常见的问题。简单来说,循环依赖是指两个或多个Bean之间互相依赖,导致程序无法正常实例化这些Bean。Spring容器通过依赖注入(DI)来管理Bean的创建与生命周期,并在遇…...

Web3 详解
1. 使用 Web3 库 Web3 是一个 JavaScript 库,可用于通过 RPC 通信与以太坊节点通信。 Web3 的工作方式是,公开已通过 RPC 启用的方法,这允许开发利用 Web3 库的用户界面,以便与部署在区块链上的合约进行交互。 一旦 Geth JavaScri…...

Spring 中依赖注入注解的区别详解
一、依赖注入的基本概念 依赖注入是一种设计模式,通过将对象的依赖以参数的形式传入类中,而不是在类中自行创建依赖对象。这样做有几个好处: 降低耦合度:类与类之间的依赖关系变得更清晰,避免了硬编码依赖。提高可测试性:通过依赖注入,可以轻松地进行单元测试,因为可以…...

PTA求一批整数中出现最多的个位数字
作者 徐镜春 单位 浙江大学 给定一批整数,分析每个整数的每一位数字,求出现次数最多的个位数字。例如给定3个整数1234、2345、3456,其中出现最多次数的数字是3和4,均出现了3次。 输入格式: 输入在第1行中给出正整数…...

探索国产编程工具:如何实现工作效率翻倍
在当前软件开发领域,国产编程工具正在迅速发展,它们在功能、性能以及用户体验上都有显著提升,以下是一些国产编程工具,它们可以帮助开发者提升工作效率。 智能代码编辑器 CodeGeeX:这是一款由清华大学和智谱AI合作开…...

秒懂:进程相关的操作
1.进程的查看 1.1创建test.cc文件,运行以下代码 #include <stdio.h> #include <sys/types.h> #include <unistd.h>int main() {while(1){sleep(1);} return 0;}1.2 执行以下命令 1. 运行test.cc文件 并将其最终的可执行文件命名为 test gcc t…...

PDF 软件如何帮助您编辑、转换和保护文件。
如何找到最好的 PDF 编辑器。 无论您是在为您的企业寻找更高效的 PDF 解决方案,还是尝试组织和编辑主文档,PDF 编辑器都可以在一个地方提供您需要的所有工具。市面上有很多 PDF 编辑器 — 在决定哪个最适合您时,请考虑这些因素。 1. 确定您的…...

蓝桥杯嵌入式国三备赛经验分享
1 学习STM32入门视频 向大家推荐一套宝藏级别的视频:【STM32入门教程-2023版 细致讲解 中文字幕】 如果已经比过蓝桥杯单片机或学习过单片机相关课程的同学,你们可以尝试不需要STM32套件进行学习。如果没有学过单片机相关课程的同学,可以买…...

AI编程工具合集
1. 简介 1.1. 概述 AI编程,即人工智能编程,是编写用于创建智能系统(如机器学习模型、自然语言处理应用程序等)的代码的过程。AI编程涉及使用算法和数据结构来实现能够执行任务的程序,这些任务通常需要人类智能才能完成。 AI编程的基础是计算机科学原理,包括数据结构、…...

[网络编程]通过java用TCP实现网络编程
文章目录 一. 通过java用TCP实现网络编程api介绍代码实现上述代码存在的问题 一. 通过java用TCP实现网络编程 api介绍 1. ServerSocket ServerSocket是专门给服务器用的api 构造方法: 方法: 2. Socket 不管是客⼾端还是服务端Socket,都是双⽅建⽴连接以后&#…...

Python(TensorFlow)和Java及C++受激发射损耗导图
🎯要点 神经网络监督去噪预测算法聚焦荧光团和检测模拟平台伪影消除算法性能优化方法自动化多尺度囊泡动力学成像生物研究多维分析统计物距粒子概率算法 Python和MATLAB图像降噪算法 消除噪声的一种方法是将原始图像与表示低通滤波器或平滑操作的掩模进行卷积。…...

IEEE投稿模板翻译
>将这一行替换为您的稿件id号(双击此处编辑)< IEEE 期刊和会议论文的撰写准备(2022) 第一作者 A. 作者,IEEE成员,第二作者 B. 作者,第三作者 C. 作者 Jr.,IEEE成员 摘要—本文档为IEEE会刊、期刊和…...

log4j 1.x 日志输出线程以唯一ID的形式配置
在 Log4j 1.x 中,直接以线程ID(如Java中的Thread.currentThread().getId()返回的ID)的形式记录日志是可行的,但 Log4j 1.x 本身并不直接提供一个内建的、自动将每个线程ID转换为“同一时间段内唯一ID”的机制。线程ID本身在JVM的上…...

宏观学习笔记:GDP分析(二)
GDP分析(一)主要是介绍GDP相关的定义以及核算逻辑,本节主要介绍GDP的分析思路。GDP分析主要是2种方法:总量分析和结构分析。 1. 总量分析 1.1 数值选择 一般情况下,分析的对象都是 官方公布的GDP当季值。 1.2 趋势规…...

两个月冲刺软考——访问位与修改位的题型(淘汰哪一页);内聚的类型;关于码制的知识点;地址映射的相关内容
1.访问位与修改位的题型(淘汰哪一页) 访问位:为1时表示在内存期间被访问过,为0时表示未被访问;修改位:为1时表示该页面自从被装入内存后被修改过,为0时表示未修改过。 置换页面时,最先置换访问位和修改位为…...

C高级编程 第十六天(树 二叉树)
1.树 1.1结构特点 非线性结构,有一个直接前驱,但可能有多个直接后继有递归性,树中还有树可以为空,即节点个数为零 1.2相关术语 根:即根结点,没有前驱叶子:即终端结点,没有后继森…...

OpenCV结构分析与形状描述符(11)椭圆拟合函数fitEllipse()的使用
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 围绕一组2D点拟合一个椭圆。 该函数计算出一个椭圆,该椭圆在最小二乘意义上最好地拟合一组2D点。它返回一个内切椭圆的旋转矩形。使…...

904.水果成篮
题目 链接:leetcode链接 思路分析(滑动窗口) 读完题目,很明显,这个题目需要我们寻找一个最长子数组,使得这个子数组里面最多存在两种不同的数字,很容易联想到使用滑动窗口。 另外ÿ…...

【网络安全】漏洞挖掘之 2FA 恢复代码安全措施不当
未经许可,不得转载。 文章目录 正文正文 目标:example.com 2024年6月,我在HackerOne上参与一个私人项目时发现了一个与2FA(双因素身份验证)恢复代码管理相关的安全漏洞。该漏洞发生在用户禁用并重新启用2FA的过程中。问题在于,系统在2FA重新启用后,仍然接受此前生成的…...

指令微调与参数微调的代码实践与分析
文章目录 指令微调的实验性分析LoRA 代码实践与分析指令微调的示例代码与预训练的代码高度一致,区别主要在于指令微调数据集的构建(SFTDataset)和序列到序列损失的计算(DataCollatorForSupervisedDataset)。以下代码展示了 LLMBox 和 YuLan-Chat 中指令微调的整体训练流程…...

Android14音频进阶之高通Elite架构指定通道播放(八十四)
简介: CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布:《Android系统多媒体进阶实战》🚀 优质专栏: Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏: 多媒体系统工程师系列【原创干货持续更新中……】🚀 优质视频课程:AAOS车载系统+…...

常见的正则化方法以及L1,L2正则化的简单描述
深度学习中的正则化是通过在模型训练过程中引入某些技术来防止模型过拟合的一种策略。过拟合是指模型在训练数据上表现非常好,但在新的、未见过的数据上表现不佳。正则化通过限制模型的复杂度或对模型参数施加约束,从而提高模型的泛化能力。 常见的正则…...

深入理解 Milvus:新一代向量数据库的基础技术与实战指南
一、什么是 Milvus? Milvus 是一个开源的向量数据库,专门设计用于存储和检索大规模的高维向量数据。无论是图像、视频、音频还是文本,通过将这些数据转换为向量,Milvus 都能通过近似最近邻搜索(Approximate Nearest N…...

Maven教程——从入门到入坑
第1章 为什么要使用Maven 1.1 获取第三方jar包 开发中需要使用到的jar包种类繁多,获取jar包的方式都不尽相同。为了查找一个jar包找遍互联网,身心俱疲。不仅如此,费劲心血找到的jar包里有的时候并没有你需要的那个类,又或者有…...

研究生深度学习入门的十天学习计划------第九天
第9天:深度学习中的迁移学习与模型微调 目标: 理解迁移学习的核心概念,学习如何在实际应用中对预训练模型进行迁移和微调,以应对不同领域的任务。 9.1 什么是迁移学习? 迁移学习(Transfer Learning&#…...