一、Servlet 核心原理与高级特性
1. 什么是 Servlet?
🌐 Servlet 是一种运行在服务器端的 Java 技术,用于处理 HTTP 请求并动态生成 Web 内容。它是 Java EE 的一部分,运行在 Servlet 容器(如 Apache Tomcat、Jetty 等)中。
Servlet 提供了一种标准化的方式来开发基于 Web 的应用程序,支持多种 HTTP 方法(如 GET、POST、PUT、DELETE 等)。
2. Servlet 的核心原理
📥 当客户端通过浏览器发送请求时,Servlet 容器会将该请求封装为 HttpServletRequest 对象,并将响应封装为 HttpServletResponse 对象。
🔄 Servlet 的生命周期由容器管理,主要包括以下几个阶段:
加载和实例化: 容器加载 Servlet 类并创建其实例。
初始化 (init): 容器调用 Servlet 的 init() 方法,完成初始化工作。
服务 (service): 容器调用 service() 方法,根据请求类型调用相应的处理方法(如 doGet() 或 doPost())。
销毁 (destroy): 当 Servlet 不再需要时,容器调用 destroy() 方法释放资源。
3. Servlet 的配置方式
传统方式:web.xml 配置
在早期的 Java Web 开发中,Servlet 的映射和初始化参数通常通过 web.xml 文件进行配置。例如:
注解方式(推荐)
自从 Java EE 6 引入了 @WebServlet 注解后,开发者可以直接在 Servlet 类上使用注解来定义 URL 映射,简化了配置过程。例如:
@WebServlet("/hello")
public class HelloWorldServlet extends HttpServlet {
// Servlet 逻辑代码
}
4. 过滤器(Filter)与监听器(Listener)
过滤器(Filter)
过滤器用于拦截和处理请求或响应,常用于日志记录、权限检查、数据压缩等场景。以下是一个简单的过滤器示例:
import jakarta.servlet.*;
import java.io.IOException;
public class LoggingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("LoggingFilter 初始化完成!");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("请求被 LoggingFilter 拦截!");
chain.doFilter(request, response); // 继续传递请求
System.out.println("响应被 LoggingFilter 拦截!");
}
@Override
public void destroy() {
System.out.println("LoggingFilter 被销毁!");
}
}
监听器(Listener)
监听器用于监听 Web 应用程序中的事件,例如应用启动、会话创建或销毁等。以下是一个监听会话创建的示例:
import jakarta.servlet.http.HttpSessionEvent;
import jakarta.servlet.http.HttpSessionListener;
public class SessionCounterListener implements HttpSessionListener {
private static int activeSessions = 0;
@Override
public void sessionCreated(HttpSessionEvent se) {
activeSessions++;
System.out.println("当前活动会话数:" + activeSessions);
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
activeSessions--;
System.out.println("当前活动会话数:" + activeSessions);
}
}
5. 异步处理(Asynchronous Processing)
在现代 Web 应用中,高并发场景下同步处理请求可能导致性能瓶颈。Servlet 3.0 引入了异步处理功能,允许 Servlet 在非阻塞模式下处理请求。
启用异步支持:
在 web.xml 中配置:
或在注解中声明:@WebServlet(urlPatterns = "/async", asyncSupported = true)
public class AsyncServlet extends HttpServlet {
// 异步逻辑代码
}
异步示例:
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
// 开启异步上下文
AsyncContext asyncContext = request.startAsync();
// 模拟耗时任务
new Thread(() -> {
try {
Thread.sleep(5000); // 模拟长时间操作
PrintWriter out = asyncContext.getResponse().getWriter();
out.println("
异步处理完成!
");out.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
asyncContext.complete(); // 完成异步操作
}
}).start();
}
6. WebSocket 支持
WebSocket 是一种全双工通信协议,适用于实时应用场景(如聊天室、在线游戏等)。Servlet 3.1 引入了对 WebSocket 的支持。
WebSocket 示例:import jakarta.websocket.OnMessage;
import jakarta.websocket.Session;
import jakarta.websocket.server.ServerEndpoint;
@ServerEndpoint("/chat")
public class ChatWebSocket {
@OnMessage
public String onMessage(String message, Session session) {
return "服务器收到消息:" + message;
}
}
7. 文件上传/下载
文件上传: 使用 Apache Commons FileUpload 或 Servlet 提供的 Part 接口处理文件上传。
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Part filePart = request.getPart("file"); // 获取上传文件
String fileName = Paths.get(filePart.getSubmittedFileName()).getFileName().toString();
// 将文件保存到指定路径
String uploadPath = getServletContext().getRealPath("/") + "uploads/" + fileName;
Files.copy(filePart.getInputStream(), Paths.get(uploadPath), StandardCopyOption.REPLACE_EXISTING);
response.getWriter().println("文件上传成功!");
}
文件下载: 设置响应头并输出文件内容。
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String filePath = getServletContext().getRealPath("/") + "files/example.pdf";
File file = new File(filePath);
if (!file.exists()) {
response.sendError(HttpServletResponse.SC_NOT_FOUND, "文件不存在!");
return;
}
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename=" + file.getName());
Files.copy(file.toPath(), response.getOutputStream());
}
二、JSP 核心原理与高级特性
1. 什么是 JSP?
🌱 JSP(JavaServer Pages)是一种基于 Servlet 的技术,允许开发者将 HTML、CSS、JavaScript 和 Java 代码混合编写,从而简化动态网页的开发过程。
2. JSP 的核心原理
🔄 JSP 文件在第一次被请求时会被 JSP 引擎编译为一个 Servlet 源文件(即 .java 文件),然后由 Servlet 容器将其编译为字节码(.class 文件)并执行。
📝 编译后的 Servlet 动态生成 HTML 内容,并将其作为响应返回给客户端。
3. JSP 表达式语言(EL)
JSP 表达式语言(Expression Language,简称 EL)是一种简洁的方式来访问后台数据。例如:${user.name}
${param.username}
4. JSTL(JSP Standard Tag Library)
JSTL 是一组标准标签库,提供了常用的页面功能,如条件判断、循环、日期格式化等。例如:<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
欢迎管理员!
${item}
5. JSP 页面间的跳转与包含
页面跳转: 使用 response.sendRedirect() 或
<%
response.sendRedirect("login.jsp");
%>
或者:
页面包含: 使用 <%@ include file="..." %> 或
<%@ include file="header.jsp" %>
6. JSP 自定义标签库(Custom Tag Libraries)
自定义标签库允许开发者创建可重用的 JSP 标签,简化页面开发。例如:
import jakarta.servlet.jsp.JspException;
import jakarta.servlet.jsp.tagext.SimpleTagSupport;
import java.io.IOException;
public class HelloTag extends SimpleTagSupport {
private String name;
public void setName(String name) {
this.name = name;
}
@Override
public void doTag() throws JspException, IOException {
getJspContext().getOut().write("Hello, " + name + "!");
}
}
配置 taglib.tld 文件后,可以在 JSP 页面中使用自定义标签:
<%@ taglib prefix="my" uri="/WEB-INF/tlds/custom.tld" %>
7. JSP 缓存机制
JSP 页面可以通过 <%@ page isCacheable="true" %> 启用缓存,减少重复计算。
使用 <%@ include file="..." flush="true" %> 可以控制包含页面的缓冲行为。
8. JSP 错误页面处理
使用 <%@ page errorPage="error.jsp" %> 指定错误页面。
在全局 web.xml 中配置错误页面映射:
三、Servlet 和 JSP 的实际应用场景
1. Servlet 的典型应用场景
用户登录验证: 使用 Servlet 处理用户提交的登录信息,并验证用户名和密码。
RESTful API: 使用 Servlet 实现 RESTful 风格的接口,提供 JSON 或 XML 格式的响应。
文件上传/下载: 使用 Servlet 处理大文件的上传和下载操作。
异步任务处理: 利用 Servlet 的异步功能处理耗时任务,提升系统性能。
2. JSP 的典型应用场景
动态页面展示: 使用 JSP 动态生成商品列表、新闻资讯等内容。
表单处理: 结合 JSP 和 Servlet,处理复杂的表单提交逻辑。
国际化支持: 使用 JSP 的资源绑定功能(ResourceBundle),实现多语言支持。
四、Servlet 和 JSP 的性能优化
1. Servlet 性能优化
减少线程竞争: 避免在 Servlet 中使用共享变量。
启用缓存: 对于静态资源或频繁访问的数据,使用缓存机制减少数据库查询。
异步处理: 利用异步功能提高并发处理能力。
合理配置线程池: 根据应用需求调整容器的线程池大小。
2. JSP 性能优化
减少内嵌脚本: 使用 JSTL 和 EL 替代 Java 脚本片段。
避免复杂逻辑: 将复杂业务逻辑移至 Servlet 或服务层。
启用 GZIP 压缩: 在容器中启用 GZIP 压缩,减少传输数据量。
使用模板引擎替代 JSP: 在复杂场景下,可以考虑使用 Thymeleaf、Freemarker 等现代模板引擎。
五、Servlet 和 JSP 的安全最佳实践
1. 输入验证
防止 SQL 注入和 XSS 攻击,确保所有用户输入经过严格验证。
使用框架提供的工具(如 Hibernate Validator)进行输入校验。
2. 会话管理
设置会话超时时间,防止会话劫持。
使用 HTTPS 加密传输敏感数据。
避免在会话中存储敏感信息。
3. 权限控制
在 web.xml 中配置安全约束:
4. 防止 CSRF 攻击
使用令牌机制(Token)验证请求来源,防止跨站请求伪造攻击。
5. 日志记录
记录关键操作日志,便于问题排查和安全审计。