Servlet基础
Servlet概述
什么是Servlet
Servlet是运行在服务器端的Java程序,用于处理客户端请求并生成响应。
Servlet的作用
- 接收客户端请求
- 处理业务逻辑
- 生成动态内容
- 返回响应给客户端
Servlet与CGI对比
| 特性 | Servlet | CGI |
|---|---|---|
| 运行方式 | 多线程 | 多进程 |
| 性能 | 高 | 低 |
| 内存占用 | 低 | 高 |
| 可移植性 | 好 | 差 |
Servlet生命周期
生命周期阶段
初始化 → 服务 → 销毁java
public class MyServlet implements Servlet {
// 1. 初始化(只执行一次)
@Override
public void init(ServletConfig config) throws ServletException {
System.out.println("Servlet初始化");
}
// 2. 服务(每次请求执行)
@Override
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
System.out.println("处理请求");
}
// 3. 销毁(只执行一次)
@Override
public void destroy() {
System.out.println("Servlet销毁");
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public String getServletInfo() {
return "MyServlet";
}
}HttpServlet
实际开发中通常继承HttpServlet:
java
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setContentType("text/html;charset=UTF-8");
resp.getWriter().write("Hello, Servlet!");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doGet(req, resp);
}
}Servlet配置方式
注解方式(Servlet 3.0+):
java
@WebServlet(
name = "helloServlet",
urlPatterns = {"/hello", "/hi"},
loadOnStartup = 1
)
public class HelloServlet extends HttpServlet {
}web.xml方式:
xml
<servlet>
<servlet-name>helloServlet</servlet-name>
<servlet-class>com.example.HelloServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>helloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>HttpServletRequest
获取请求信息
java
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// 获取请求行信息
String method = req.getMethod(); // GET/POST
String uri = req.getRequestURI(); // /app/hello
String url = req.getRequestURL().toString(); // http://localhost/app/hello
String protocol = req.getProtocol(); // HTTP/1.1
String contextPath = req.getContextPath(); // /app
String servletPath = req.getServletPath(); // /hello
// 获取请求头
String host = req.getHeader("Host");
String userAgent = req.getHeader("User-Agent");
Enumeration<String> headerNames = req.getHeaderNames();
// 获取请求参数
String name = req.getParameter("name");
String[] hobbies = req.getParameterValues("hobby");
Map<String, String[]> params = req.getParameterMap();
// 获取客户端信息
String remoteAddr = req.getRemoteAddr();
String remoteHost = req.getRemoteHost();
int remotePort = req.getRemotePort();
}请求转发
java
// 请求转发(服务器内部跳转,URL不变)
req.getRequestDispatcher("/target").forward(req, resp);请求包含
java
// 请求包含(合并多个Servlet的输出)
req.getRequestDispatcher("/header").include(req, resp);
resp.getWriter().write("主内容");
req.getRequestDispatcher("/footer").include(req, resp);获取请求体
java
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// 设置请求编码
req.setCharacterEncoding("UTF-8");
// 获取请求体(适用于JSON等)
BufferedReader reader = req.getReader();
StringBuilder sb = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
sb.append(line);
}
String body = sb.toString();
}HttpServletResponse
设置响应信息
java
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// 设置状态码
resp.setStatus(200);
resp.setStatus(HttpServletResponse.SC_OK);
// 设置响应头
resp.setHeader("Content-Type", "text/html;charset=UTF-8");
resp.setHeader("Cache-Control", "no-cache");
// 设置内容类型
resp.setContentType("text/html;charset=UTF-8");
// 设置编码
resp.setCharacterEncoding("UTF-8");
// 输出内容
PrintWriter writer = resp.getWriter();
writer.write("<h1>Hello, World!</h1>");
// 输出字节(用于文件下载等)
ServletOutputStream out = resp.getOutputStream();
out.write("Hello".getBytes());
}重定向
java
// 重定向(客户端跳转,URL改变)
resp.sendRedirect("/app/target");文件下载
java
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String fileName = "test.txt";
String filePath = "/WEB-INF/files/" + fileName;
// 设置响应头
resp.setContentType("application/octet-stream");
resp.setHeader("Content-Disposition",
"attachment; filename=" + URLEncoder.encode(fileName, "UTF-8"));
// 读取文件并输出
InputStream in = getServletContext().getResourceAsStream(filePath);
ServletOutputStream out = resp.getOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
in.close();
out.close();
}Session与Cookie
Cookie
java
// 创建Cookie
Cookie cookie = new Cookie("username", "张三");
cookie.setMaxAge(60 * 60 * 24); // 有效期24小时
cookie.setPath("/"); // 有效路径
cookie.setHttpOnly(true); // 防止XSS攻击
cookie.setSecure(true); // 仅HTTPS传输
// 添加到响应
resp.addCookie(cookie);
// 获取Cookie
Cookie[] cookies = req.getCookies();
if (cookies != null) {
for (Cookie c : cookies) {
String name = c.getName();
String value = c.getValue();
}
}
// 删除Cookie
Cookie cookie = new Cookie("username", "");
cookie.setMaxAge(0);
resp.addCookie(cookie);Session
java
// 获取Session
HttpSession session = req.getSession(); // 没有则创建
HttpSession session = req.getSession(false); // 没有则返回null
// 存储数据
session.setAttribute("user", user);
// 获取数据
User user = (User) session.getAttribute("user");
// 删除数据
session.removeAttribute("user");
// 销毁Session
session.invalidate();
// Session配置
session.setMaxInactiveInterval(30 * 60); // 30分钟超时
// Session ID
String sessionId = session.getId();Session vs Cookie
| 特性 | Session | Cookie |
|---|---|---|
| 存储位置 | 服务器 | 客户端 |
| 安全性 | 高 | 低 |
| 存储容量 | 大 | 小(4KB) |
| 性能影响 | 占用服务器内存 | 无 |
Filter过滤器
Filter概述
Filter用于拦截请求和响应,可以在请求到达Servlet之前或响应返回客户端之前进行处理。
Filter实现
java
@WebFilter("/*")
public class EncodingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("Filter初始化");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// 请求前处理
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
// 放行
chain.doFilter(request, response);
// 响应后处理
System.out.println("响应处理完成");
}
@Override
public void destroy() {
System.out.println("Filter销毁");
}
}Filter配置
java
@WebFilter(
urlPatterns = {"/*"},
servletNames = {"helloServlet"},
initParams = {@WebInitParam(name = "encoding", value = "UTF-8")}
)
public class MyFilter implements Filter {
}Filter链
请求 → Filter1 → Filter2 → Filter3 → Servlet
响应 ← Filter1 ← Filter2 ← Filter3 ← Servlet常见Filter应用
登录验证过滤器:
java
@WebFilter("/admin/*")
public class AuthFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
HttpSession session = req.getSession(false);
if (session == null || session.getAttribute("user") == null) {
resp.sendRedirect(req.getContextPath() + "/login");
return;
}
chain.doFilter(request, response);
}
}Listener监听器
Listener类型
| 类型 | 接口 | 说明 |
|---|---|---|
| ServletContext | ServletContextListener | 应用启动/关闭 |
| ServletContext | ServletContextAttributeListener | 应用属性变化 |
| HttpSession | HttpSessionListener | Session创建/销毁 |
| HttpSession | HttpSessionAttributeListener | Session属性变化 |
| ServletRequest | ServletRequestListener | 请求创建/销毁 |
| ServletRequest | ServletRequestAttributeListener | 请求属性变化 |
ServletContextListener
java
@WebListener
public class AppListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("应用启动");
// 初始化操作
ServletContext context = sce.getServletContext();
context.setAttribute("appPath", context.getContextPath());
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("应用关闭");
// 清理操作
}
}HttpSessionListener
java
@WebListener
public class SessionListener implements HttpSessionListener {
private static int onlineCount = 0;
@Override
public void sessionCreated(HttpSessionEvent se) {
onlineCount++;
System.out.println("在线人数: " + onlineCount);
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
onlineCount--;
System.out.println("在线人数: " + onlineCount);
}
}Servlet 6.1新特性
Jakarta EE 11
Servlet 6.1要求Jakarta EE 11,包名从javax.*改为jakarta.*:
java
// 旧版本
import javax.servlet.*;
import javax.servlet.http.*;
// 新版本
import jakarta.servlet.*;
import jakarta.servlet.http.*;新特性
- HttpOnly Cookie属性增强
- 改进的WebSocket支持
- HTTP/2增强
- 新的API简化
下一步
继续学习 Spring框架简介,了解Spring生态体系。