【Java WEB】请求对象&响应对象

个人主页:Hello Code.
本文专栏:《Java WEB从入门到实战》
Java WEB完整内容请点击前往Java WEB从入门到实战 查看
如有问题,欢迎指正,一起学习~~


文章目录

    • 请求对象
      • 获取各种路径
      • 获取请求头
      • 获取请求参数信息
      • 流对象获取请求信息
      • 中文乱码问题
      • 请求域
      • 请求转发
      • 请求包含
    • 响应对象
      • 常见状态码
      • 字节流响应消息
      • 字符流响应消息
      • 响应图片
      • 设置缓存
      • 定时刷新
      • 请求重定向
      • 文件下载
    • 学生管理系统2


请求对象

请求: 获取资源。在BS架构中,就是客户端浏览器向服务端发出询问。

请求对象: 就是在项目中用于发送请求的对象(ServletRequestHttpServletRequest)

ServletRequest 和 HttpServletRequest 都是接口,但是Tomcat 服务器会帮我们处理好实现类的赋值等工作,我们不需要关心这些

获取各种路径

返回值 方法名 说明
String getContextPath() 获取虚拟目录名称
String getServletPath() 获取Servlet映射路径
String getRemoteAddr() 获取访问者ip地址
String getQueryString() 获取请求的消息数据
String getRequestURI() 获取统一资源标识符
StringBuffer getRequestURL() 获取统一资源定位符
package study.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@WebServlet("/request")
public class RequestDemo extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String contextPath = req.getContextPath();
        String servletPath = req.getServletPath();
        String remoteAddr = req.getRemoteAddr();
        String queryString = req.getQueryString();
        String requestURI = req.getRequestURI();
        StringBuffer requestURL = req.getRequestURL();

        PrintWriter pw = resp.getWriter();
        pw.println("contextPath= " + contextPath);
        pw.println("servletPath= " + servletPath);
        pw.println("remoteAddr= " + remoteAddr);
        pw.println("queryString= " + queryString);
        pw.println("requestURI= " + requestURI);
        pw.println("requestURL= " + requestURL);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}

获取请求头

返回值 方法名 说明
String getHeader(String name) 根据请求头名称获取一个值
Enumeration getHeaders(String name) 根据请求头名称获取多个值
Enumeration getHeaderNames() 获取所有请求头名称
package study.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;

@WebServlet("/request2")
public class RequestDemo2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println(req.getHeader("host"));
        System.out.println(req.getHeader("user-agent"));
        Enumeration<String> headers = req.getHeaders("user-agent");
        while(headers.hasMoreElements()){
            String s = headers.nextElement();
            System.out.println(s);
        }
        System.out.println("===============");
        Enumeration<String> names = req.getHeaderNames();
        while(names.hasMoreElements()){
            System.out.println(names.nextElement());
        }
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}

获取请求参数信息

返回值 方法名 说明
String getParameter(String name) 根据名称获取数据
String[] getParameterValues(String name) 根据名称获取所有数据
Enumeration getParameterNames() 获取所有名称
Map getParameterMap() 获取所有参数的键值对
package study.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.swing.*;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Map;
import java.util.Set;

@WebServlet("/request3")
public class RequestDemo3 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println(req.getParameter("username"));
        System.out.println("================");
        for (String hobby : req.getParameterValues("hobby")) {
            System.out.println(hobby);
        }
        System.out.println("===================");
        Enumeration<String> parameterNames = req.getParameterNames();
        while(parameterNames.hasMoreElements()){
            String name = parameterNames.nextElement();
            for (String value : req.getParameterValues(name)) {
                System.out.println(value);
            }
        }
        System.out.println("===================");
        Map<String, String[]> parameterMap = req.getParameterMap();
        for (String key : parameterMap.keySet()) {
            String[] value = parameterMap.get(key);
            System.out.println(key + " === " + value);
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}

获取请求参数并封装对象

  1. 手动封装方式
    成员变量名称和参数name属性值保持一致
  2. 反射封装方式
    属性描述器:PropertyDescriptor(根据名称获取到对象中对应的get和set方法)
  3. 工具类封装方式
    beanutils工具类,populate方法
    在发布之前,还需要进入File-Project Structure
    【Java WEB】请求对象&响应对象_第1张图片
package study.servlet;

import study.servlet.bean.Student;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;

/*
*   封装对象------反射方式
* */
public class RequestDemo5 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取所有数据
        Map<String, String[]> map = req.getParameterMap();
        // 封装学生对象
        Student stu = new Student();
        // 遍历集合
        for(String name : map.keySet()){
            String[] value = map.get(name);
            try {
                // 获取Student对象的属性描述器
                PropertyDescriptor pd = new PropertyDescriptor(name, stu.getClass());
                // 获取对应的set方法
                Method writeMethod = pd.getWriteMethod();
                // 执行方法
                writeMethod.invoke(stu,value);
            } catch (IntrospectionException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}
package study.servlet;

import org.apache.commons.beanutils.BeanUtils;
import study.servlet.bean.Student;

/*
*   封装对象------工具类方式
	需要导包:BeanUtils
* */
public class RequestDemo6 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取所有数据
        Map<String, String[]> map = req.getParameterMap();
        // 封装学生对象
        Student stu = new Student();
        try {
            BeanUtils.populate(stu, map);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}

流对象获取请求信息

返回值 方法名 说明
BufferedReader getReader() 获取字符输入流
ServletInputStream getInputStream() 获取字节输入流

用IO流获取请求信息时,不支持get方式,只支持post提交方式
获得到的流对象都不是自己new出来的,不需要close释放资源,会由请求对象处理并释放

package study.servlet;

import org.apache.commons.beanutils.BeanUtils;
import study.servlet.bean.Student;

import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.Map;

/*
*   流对象获取数据
* */
@WebServlet("/request7")
public class RequestDemo7 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 字符流(必须是post请求方式)
        BufferedReader br = req.getReader();
        String line;
        while((line = br.readLine()) != null) System.out.println(line);
        
        // 字节流
        ServletInputStream is = req.getInputStream();
        byte[] arr = new byte[1024];
        int len;
        while((len = is.read(arr)) != -1){
            System.out.println(new String(arr, 0, len));
        }
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}

中文乱码问题

  • GET方式
    没有乱码问题,在Tomcat 8 版本后已经解决
  • POST方式
    有乱码问题,可以通过 setCharacterEncoding() 方法来解决(编码格式要和页面编码格式一致)
package study.servlet;

/*
*   中文乱码问题
* */
@WebServlet("/request8")
public class RequestDemo8 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        String name = req.getParameter("name");
        System.out.println(name);
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}

请求域

  • 请求域(request域):可以在一次请求范围内进行共享数据。
  • 一般用于请求转发的多个资源中共享数据
  • 请求对象操作共享数据方法
    返回值 方法名 说明
    void setAttribute(String name, Object value) 向请求域对象中存储数据
    Object getAttribute(String name) 通过名称获取请求域对象中的数据
    void removeAttribute(String name) 通过名称移除请求域对象中的数据

请求转发

  • 请求转发:客户端的一次请求到达以后,发现需要借助其他 Servlet 来实现功能(浏览器请求,A发现做不了,转发给B去做)
  • 特点
    • 浏览器地址栏不变
    • 域对象中的数据不丢失
    • 负责转发的Servlet 转发前后的响应正文会丢失
    • 由转发的目的地来响应客户端
返回值 方法名 说明
RequestDispatcher getRequestDispatcher(String name) 获取请求调度对象
void forward(ServletRequest req, ServletResponse resp) 实现转发(用请求调度对象调用)
package study.servlet.request;

/*
*   请求转发
* */
@WebServlet("/request9")
public class RequestDemo9 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 设置共享数据
        req.setAttribute("name","张三");
        // 获取请求调度对象
        RequestDispatcher rd = req.getRequestDispatcher("/request10");
        // 请求转发
        rd.forward(req, resp);
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}
package study.servlet.request;

/*
*   转发目的
* */
@WebServlet("/request10")
public class RequestDemo10 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取共享数据
        System.out.println(req.getAttribute("name"));
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}

请求包含

  • 请求包含:可以合并其他Servlet 中的功能一起响应给客户端(浏览器请求,A只能做一半,另一半让B做)
  • 特点
    • 浏览器地址栏不变
    • 域对象中的数据不丢失
    • 被包含的 Servlet 响应头会丢失
返回值 方法名 说明
RequestDispatcher getRequestDispatcher(String name) 获取请求调度对象
void include(ServletRequest req, ServletResponse resp) 实现包含
package study.servlet.request;

/*
*   请求包含
* */
@WebServlet("/request11")
public class RequestDemo11 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 设置共享数据
        req.setAttribute("name","张三");
        // 获取请求调度对象
        RequestDispatcher rd = req.getRequestDispatcher("/request10");
        // 请求转发
        rd.include(req, resp);
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}

响应对象

  • 响应:回馈结果。在 BS 架构中,就是服务器给客户浏览器反馈结果
  • 响应对象:就是在项目中用于发送响应的对象
    ServletResponse(接口)
    HttpServletResponse(继承自ServletResponse,基于http协议的接口)

    和请求对象一样,不需要我们去写实现类,在Tomcat 服务器创建好,在执行 doGet 或者 doPost 方法时,服务器会把相应的实现类对象传递

常见状态码

状态码 说明
200 成功
302 重定向
304 请求资源未改变,使用缓存
400 请求错误,常见于请求参数错误
404 请求资源未找到
405 请求方式不支持
500 服务器错误

字节流响应消息

返回值 方法名 说明
ServletOutputStream getOutputStream() 获取响应字节输出流对象
void setContentType(“text/html;charset=UTF-8”) 设置响应内容类型,解决中文乱码问题

步骤:

  1. 获取字节输出流对象
  2. 定义一个消息(一个字符串)
  3. 通过字节流对象输出

获取到的字节输出流对象不需要close释放,会由响应对象处理并释放

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
	// 获取字节输出流
	ServletOutputStream os = resp.getOutputStream();
	String s = "字节输出流响应消息";
	os.write(s.getBytes());
}

未出现乱码问题:浏览器默认gbk编码,idea默认UTF-8编码;但是getBytes方法在将字符串转为字节数组时,如果不传递参数指定编码,就会根据当前系统平台默认编码进行转换,Windows系统默认编码为gbk,和浏览器一致,故未出现乱码

// 统一编码格式为UTF-8并解决乱码问题
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
	// 设置相应内容类型,并设置编码格式(告知浏览器应该采用的编码格式)
	resp.setContentType("text/html;charset=UTF-8");
	// 获取字节输出流
	ServletOutputStream os = resp.getOutputStream();
	String s = "字节输出流响应消息";
	os.write(s.getBytes("UTF-8"));
}

字符流响应消息

返回值 方法名 说明
PrintWriter getWriter() 获取响应字符输出流对象
void setContentType(“text/html;charset=UTF-8”) 设置响应内容类型,解决中文乱码问题

步骤和上面字节流一样,同样不需要自己close释放资源

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
	// 设置相应内容类型,并设置编码格式(告知浏览器应该采用的编码格式)
	resp.setContentType("text/html;charset=UTF-8");
	// 获取字符输出流对象
	PrintWriter pw = resp.getWriter();
	pw.write("字符输出流响应消息");
}

响应图片

  1. 通过文件的相对路径获取绝对路径(getRealPath)
  2. 创建字节输入流对象,关联读取的图片路径
  3. 通过响应对象获取字节输出流对象
  4. 循环读取和写出图片
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
	String realPath = getServletContext().getRealPath("/img/tx.png");
	// 创建字节输入流对象,关联图片
	BufferedInputStream is = new BufferedInputStream(new FileInputStream(realPath));
	// 获取字节输出流对象,响应图片
	ServletOutputStream os = resp.getOutputStream();
	// 循环读写
	byte[] arr = new byte[1024];
	int len;
	while((len = is.read(arr)) != -1){
		os.write(arr, 0, len);
	}
	// 释放资源
	is.close();
}

设置缓存

  • 缓存:对于不经常变化的数据,我们可以设置合理的缓存时间,以避免浏览器频繁请求服务器。以此来提高效率
返回值 方法名 说明
void setDateHeader(String name,long time) 设置消息头添加缓存

例:resp.setDateHeader("Expires",System.currentTimeMillis() + 1*60*60*1000); 设置一个小时缓存时间
Expires 就是过期的意思
时间单位为毫秒,1秒等于1000毫秒

定时刷新

  • 定时刷新:过了指定时间后,页面自动进行跳转
返回值 方法名 说明
void setHeader(String name,String value) 设置消息头定时刷新

例:resp.setHeader("Refresh","3;URL=要跳转的路径")
单位为秒

请求重定向

  • 请求重定向:客户端的一次请求到达后,发现需要借助其他Servlet 来实现功能
  • 特点:浏览器地址栏会发生改变,两次请求,请求域对象中不能共享数据,可以重定向到其他服务器
  • 重定向实现原理
    1. 设置响应状态码为302:resp.setStatus(302);
    2. 设置响应的资源路径(响应到哪里去,通过响应消息头 location 来指定):resp.setHeader("location","/response/responseDemo")
  • 响应对象重定向方法
    返回值 方法名 说明
    void sendRedirect(String name) 设置重定向

文件下载

  1. 创建字节输入流,关联读取的文件
  2. 设置响应消息头支持的类型:resp.setHeader("Content-Type","application/octet-stream")
    Content-Type:消息头名称,代表所支持的类型
    application/octet-stream:消息头参数,代表应用的类型为字节流
  3. 设置响应消息头以下载方式打开资源:resp.setHeader("Content-Disposition","attachment;filename=下载的文件名称")
    Content-Disposition:消息头名称,代表处理形式
    attachment;filename=xxx:消息头参数,代表附件的形式进行处理,filename代表指定下载文件的名称
  4. 通过响应对象获取字节输出流对象
  5. 循环读写
  6. 释放资源
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
	// 创建字节输入流,关联读取的文件
	String realPath = req.getServletContext().getRealPath("/img/tx.png");
	BufferedInputStream bis = new BufferedInputStream(new FileInputStream(realPath));
	// 设置响应消息头支持的类型
	resp.setHeader("Content-Type", "application/octet-stream");
	// 设置响应消息头以下载方式打开资源
	resp.setHeader("Content-Disposition","attachment;filename=file.png");
	// 通过响应对象获取字节输出流对象
	ServletOutputStream os = resp.getOutputStream();
	int len;
	byte[] arr = new byte[1024];
	while((len = bis.read(arr)) != -1){
		os.write(arr, 0, len);
	}
	// 释放资源
	bis.close();
}

学生管理系统2

  1. 创建一个 web 项目
  2. 在web 目录下创建一个 index.html,包含两个超链接标签(添加学生、查看学生)
  3. 在 web目录下创建一个 addStudent.html,用于实现添加功能的表单页面
  4. 在 src 下创建一个 Student 类,用于封装学生信息
// list.java
package studentServlet;

import studentServlet.bean.Student;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.ArrayList;
@WebServlet("/list")
public class list extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        BufferedReader br = new BufferedReader(new FileReader("E:\\Java\\code\\StudentServlet\\stu.txt"));
        ArrayList<Student> list = new ArrayList<>();
        String str;
        while((str = br.readLine()) != null){
            String[] split = str.split(",");
            Student stu = new Student(split[0], Integer.parseInt(split[1]), Integer.parseInt(split[2]));
            list.add(stu);
        }
        resp.setContentType("text/html;charset=UTF-8");
        PrintWriter pw = resp.getWriter();
        for(Student student : list){
            pw.write(student.getUsername() + "," + student.getAge() + "," + student.getScore());
            pw.write("
"
); } br.close(); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req,resp); } }


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>学生信息管理系统title>
head>
<body>
    <h1>学生信息管理系统h1>
    <hr>
    <a href="/studentAdd.html">添加学生信息a>
    <a href="/list">查看学生信息a>
body>
html>

推荐阅读:【Java WEB】Cookie & Session & JSP

你可能感兴趣的:(Java,WEB从入门到实战,java,开发语言,后端)