Servlet 中 Request、Response 和 Session 的详细介绍

175 阅读6分钟

Servlet 中 Request、Response 和 Session 的详细介绍

在 Java Web 开发中,ServletRequest、ServletResponse 和 HttpSession 是三个核心对象,它们分别负责处理客户端请求、服务器响应以及用户会话管理。下面对这三个对象进行详细介绍。

一、ServletRequest/HttpServletRequest

ServletRequest 是一个接口,代表客户端的请求信息,而 HttpServletRequest 是它的子接口,专门用于 HTTP 协议的请求。

1. 主要功能

  • 获取请求的基本信息(如 URL、URI、请求方法等)
  • 获取请求参数(表单数据、URL 参数等)
  • 获取请求头信息
  • 获取客户端信息
  • 在请求作用域中存储和获取属性
  • 获取请求的输入流

2. 常用方法

2.1 获取请求基本信息
// 获取请求方法(GET、POST 等)
String method = request.getMethod();

// 获取请求的 URI(不包含协议、主机名和端口)
String uri = request.getRequestURI();

// 获取完整的请求 URL
StringBuffer url = request.getRequestURL();

// 获取上下文路径(项目的虚拟路径)
String contextPath = request.getContextPath();

// 获取请求路径(不包含上下文路径)
String servletPath = request.getServletPath();
2.2 获取请求参数
// 获取单个参数值
String username = request.getParameter("username");

// 获取多个参数值(如复选框)
String[] hobbies = request.getParameterValues("hobby");

// 获取所有参数名
Enumeration<String> paramNames = request.getParameterNames();
while(paramNames.hasMoreElements()) {
    String paramName = paramNames.nextElement();
    String paramValue = request.getParameter(paramName);
    // 处理参数...
}

// 获取所有参数的 Map
Map<String, String[]> paramMap = request.getParameterMap();
2.3 获取请求头信息
// 获取单个请求头值
String userAgent = request.getHeader("User-Agent");

// 获取所有请求头名称
Enumeration<String> headerNames = request.getHeaderNames();
while(headerNames.hasMoreElements()) {
    String headerName = headerNames.nextElement();
    String headerValue = request.getHeader(headerName);
    // 处理请求头...
}
2.4 获取客户端信息
// 获取客户端 IP 地址
String clientIp = request.getRemoteAddr();

// 获取客户端端口号
int clientPort = request.getRemotePort();
2.5 请求属性操作
// 设置请求属性(可在请求转发时传递数据)
request.setAttribute("userInfo", userInfo);

// 获取请求属性
UserInfo userInfo = (UserInfo) request.getAttribute("userInfo");
2.6 请求转发
// 获取请求转发器
RequestDispatcher dispatcher = request.getRequestDispatcher("/targetServlet");

// 执行转发(同一个请求)
dispatcher.forward(request, response);

二、ServletResponse/HttpServletResponse

ServletResponse 是一个接口,代表服务器对客户端的响应,而 HttpServletResponse 是它的子接口,专门用于 HTTP 协议的响应。

1. 主要功能

  • 设置响应状态码
  • 设置响应头
  • 向客户端输出数据
  • 实现请求重定向
  • 设置内容类型和编码格式

2. 常用方法

2.1 设置响应内容
// 获取字符输出流
PrintWriter writer = response.getWriter();

// 输出内容到客户端
writer.write("Hello, World!");
writer.println("<h1>Welcome</h1>");
writer.flush();
writer.close();

// 获取字节输出流(用于二进制数据,如图片、文件等)
ServletOutputStream outputStream = response.getOutputStream();
outputStream.write("Hello, World!".getBytes());
outputStream.flush();
outputStream.close();
2.2 设置内容类型和编码
// 设置内容类型和编码格式(解决中文乱码问题)
response.setContentType("text/html;charset=utf-8");

// 仅设置响应的字符编码
response.setCharacterEncoding("utf-8");

// 设置响应的内容类型为 JSON
response.setContentType("application/json;charset=utf-8");
2.3 请求重定向
// 重定向到其他资源(客户端跳转,会发送新的请求)
response.sendRedirect("/login");

// 或者重定向到完整 URL
response.sendRedirect("https://www.example.com");
2.4 设置响应头
// 设置单个响应头
response.setHeader("Refresh", "3;url=/index");  // 3秒后刷新并跳转到/index

// 添加响应头
response.addHeader("Cache-Control", "no-cache");

// 设置内容长度
response.setContentLength(1024);

// 设置文件下载响应头
response.setHeader("Content-Disposition", "attachment;filename=example.zip");
2.5 设置状态码
// 设置 HTTP 状态码
response.setStatus(404);  // 未找到资源
response.setStatus(302);  // 临时重定向

// 发送错误状态码及错误信息
response.sendError(403, "Forbidden: You don't have permission");

三、HttpSession

HttpSession 是一个接口,代表客户端与服务器之间的会话。会话是指一个用户从第一次访问服务器开始,到最后一次访问服务器结束的整个过程。

1. 主要功能

  • 在多次请求之间保存用户状态和数据
  • 识别同一客户端的多次请求
  • 存储用户登录信息和临时数据

2. 常用方法

2.1 获取 Session 对象
// 获取当前请求的会话,如果没有则创建新会话
HttpSession session = request.getSession();

// 获取当前请求的会话,如果没有则返回 null
HttpSession session = request.getSession(false);
2.2 Session 属性操作
// 设置 Session 属性
User user = new User("admin", "admin@example.com");
session.setAttribute("user", user);

// 获取 Session 属性
User currentUser = (User) session.getAttribute("user");

// 移除 Session 属性
session.removeAttribute("user");

// 获取所有 Session 属性名
Enumeration<String> attributeNames = session.getAttributeNames();
while(attributeNames.hasMoreElements()) {
    String attributeName = attributeNames.nextElement();
    Object attributeValue = session.getAttribute(attributeName);
    // 处理属性...
}
2.3 Session 生命周期管理
// 获取 Session 创建时间(毫秒时间戳)
long creationTime = session.getCreationTime();

// 获取最后一次访问时间
long lastAccessedTime = session.getLastAccessedTime();

// 获取 Session ID
String sessionId = session.getId();

// 检查 Session 是否为新创建的
boolean isNew = session.isNew();

// 设置 Session 最大不活动时间(秒)
session.setMaxInactiveInterval(3600);  // 1小时

// 立即使 Session 失效
session.invalidate();

四、Request、Response 和 Session 的作用域比较

对象作用域生命周期特点
Request请求作用域一次请求(从客户端发送请求到服务器返回响应)数据只能在本次请求内共享,常用于请求转发时传递数据
Session会话作用域一次会话(从用户首次访问到会话超时或注销)数据可以在同一个用户的多次请求之间共享,常用于保存用户登录状态
ServletContext应用作用域整个应用程序(从服务器启动到服务器关闭)数据可以在整个应用程序的所有用户之间共享,常用于保存全局配置信息

五、使用示例

1. 表单处理与会话管理

@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        // 设置请求编码
        request.setCharacterEncoding("UTF-8");
        
        // 获取表单参数
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        
        // 验证用户(实际应用中应查询数据库)
        if ("admin".equals(username) && "123456".equals(password)) {
            // 登录成功,创建用户对象并保存到 Session
            User user = new User(username, "admin@example.com");
            HttpSession session = request.getSession();
            session.setAttribute("user", user);
            
            // 设置会话超时时间为30分钟
            session.setMaxInactiveInterval(1800);
            
            // 重定向到首页
            response.sendRedirect("/home");
        } else {
            // 登录失败,设置错误信息并转发回登录页面
            request.setAttribute("error", "用户名或密码错误");
            request.getRequestDispatcher("/login.jsp").forward(request, response);
        }
    }
}

2. 中文输出示例

@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        // 设置响应内容类型和编码,解决中文乱码
        response.setContentType("text/html;charset=utf-8");
        
        // 获取输出流
        PrintWriter out = response.getWriter();
        
        // 输出中文内容
        out.println("<html>");
        out.println("<head><title>中文示例</title></head>");
        out.println("<body>");
        out.println("<h1>你好,世界!</h1>");
        
        // 从会话中获取用户信息(如果存在)
        HttpSession session = request.getSession(false);
        if (session != null && session.getAttribute("user") != null) {
            User user = (User) session.getAttribute("user");
            out.println("<p>欢迎回来," + user.getUsername() + "!</p>");
        }
        
        out.println("</body>");
        out.println("</html>");
    }
}

六、注意事项

  1. 编码问题:在处理表单数据或输出中文内容时,务必设置正确的编码格式,避免中文乱码。

  2. Session 管理:合理设置 Session 超时时间,避免资源浪费;对于敏感操作,验证 Session 是否存在有效用户。

  3. 请求转发与重定向

    • 请求转发(forward)是服务器内部跳转,地址栏不变,只发送一次请求
    • 重定向(redirect)是客户端跳转,地址栏改变,发送两次请求
  4. 资源释放:使用输出流(如 PrintWriter、ServletOutputStream)后应及时关闭,避免资源泄漏。

  5. 属性作用域:根据数据共享范围的需求,选择合适的作用域(request、session、servletContext)来存储数据。

通过合理使用 Request、Response 和 Session 对象,我们可以构建功能完善的 Web 应用程序,实现用户交互、数据处理和状态管理等核心功能。