Skip to content

Servlet基础

Servlet概述

什么是Servlet

Servlet是运行在服务器端的Java程序,用于处理客户端请求并生成响应。

Servlet的作用

  • 接收客户端请求
  • 处理业务逻辑
  • 生成动态内容
  • 返回响应给客户端

Servlet与CGI对比

特性ServletCGI
运行方式多线程多进程
性能
内存占用
可移植性

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

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();
特性SessionCookie
存储位置服务器客户端
安全性
存储容量小(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类型

类型接口说明
ServletContextServletContextListener应用启动/关闭
ServletContextServletContextAttributeListener应用属性变化
HttpSessionHttpSessionListenerSession创建/销毁
HttpSessionHttpSessionAttributeListenerSession属性变化
ServletRequestServletRequestListener请求创建/销毁
ServletRequestServletRequestAttributeListener请求属性变化

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.*;

新特性

  1. HttpOnly Cookie属性增强
  2. 改进的WebSocket支持
  3. HTTP/2增强
  4. 新的API简化

下一步

继续学习 Spring框架简介,了解Spring生态体系。