1、接收请求数据的流程
- 浏览器发送HTTP请求到Tomcat服务器
- HTTP的请求中会包含很多请求数据(请求行+请求头+请求体)
- Tomcat服务器会对HTTP请求中的数据进行解析并把解析结果存入到一个对象中
- 所封装的对象即为Request对象,所以可以从Request对象中获取请求的的所有信息,如请求头、请求参数、请求路径、会话信息等
- 获取到数据后就可以继续后续的业务,比如获取用户名和密码就可以实现登录操作
2、Request对象
Request对象是一个包含客户端发送给服务器端的所有信息的对象。它是Servlet的一个核心组件,用于收集客户端发送的表单数据、Cookies、超链接等信息,以及获取与客户端请求相关的其他数据,如请求方式、请求头信息、请求参数等。
作用是与客户端进行交互,它允许Servlet获取并处理来自客户端的请求数据。通过Request对象,Servlet可以了解客户端的请求细节,并根据这些请求数据生成相应的响应。
作用域是一次请求。在一次请求中,Servlet可以使用Request对象来获取和处理请求数据,并根据需要构建响应对象(Response对象)来发送回客户端。
3、方法
当客户端发送一个HTTP请求到Servlet时,Servlet容器(Tomcat)会自动创建一个实现了HTTPServletRequest接口的对象,这个对象包含了请求的所有信息(如请求头、请求参数、请求路径等),并将这个对象传递给Servlet的doGet()、doPost()等方法,让Servlet能够处理这个请求。Servlet容器负责管理和调用Servlet处理请求。由于不需要直接实现这个接口,而是使用Servlet容器提供的实例,所以只需要关注怎样使用接口提供的方法处理请求。
HTTP请求数据中包含了请求行、请求头、请求体,分别用各自的API方法获取对应的值:
1)请求行
请求行包括三块内容:请求方式、请求资源路径、HTTP协议及版本。
- getMethod():获取请求方式
- getRequestURL():获取客户端发出请求时的完整URL
- getRequestURI():获取请求行中的资源名称部分(项目名称开始)
- getQueryString():获取请求行中的参数部分(GET请求)
- getProtocol():获取HTTP版本号
- getContextPath():获取请求的上下文路径
应用举例:
@WebServlet("/req1")
public class RequestDemo1 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// String getMethod():获取请求方式: GETString method = req.getMethod();System.out.println(method);//GET// String getContextPath():获取虚拟目录(项目访问路径):/request-demoString contextPath = req.getContextPath();System.out.println(contextPath);// StringBuffer getRequestURL(): 获取URL(统一资源定位符):http://localhost:8080/request-demo/req1StringBuffer url = req.getRequestURL();System.out.println(url.toString());// String getRequestURI():获取URI(统一资源标识符): /request-demo/req1String uri = req.getRequestURI();System.out.println(uri);// String getQueryString():获取请求参数(GET方式): username=zhangsanString queryString = req.getQueryString();System.out.println(queryString);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {}
}
启动服务器,访问http://localhost:8080/request-demo/req1?username=zhangsan&passwrod=123,获取的结果如下:
2)请求头
请求头的数据格式是 key: value的键值对。
- getHeader(String name)根据请求头名称获取其对应的值
应用举例:
//获取请求头: user-agent: 浏览器的版本信息String agent = req.getHeader("user-agent");
3)请求体
(POST请求)
对于POST请求,特别是当内容类型是application/json、application/xml或text/plain等时,请求体可能包含重要的数据,如JSON对象或XML文档。在这种情况下,获取请求体是非常常见的。
先获取流对象,再从流对象中拿数据。
- BufferedReader getReader():获取字符输入流(纯文本)
BufferedReader reader = request.getReader();
String line;
StringBuilder requestBody = new StringBuilder();
while ((line = reader.readLine()) != null) { requestBody.append(line);
}
String body = requestBody.toString();
- ServletInputStream getInputStream():获取字节输入流
InputStream inputStream = request.getInputStream();
byte[] buffer = new byte[1024];
int bytesRead;
StringBuilder requestBody = new StringBuilder();
while ((bytesRead = inputStream.read(buffer)) != -1) { requestBody.append(new String(buffer, 0, bytesRead));
}
String body = requestBody.toString();
- 对于JSON请求体,还可以使用JSON处理库(如Jackson或Gson)解析请求体为Java对象:
import com.fasterxml.jackson.databind.ObjectMapper; ObjectMapper objectMapper = new ObjectMapper();
MyObject myObject = objectMapper.readValue(request.getInputStream(), MyObject.class);//注:ObjectMapper类是Jackson库中的一个核心类,它用于在Java对象和JSON数据之间进行转换。
//Jackson 是一个流行的Java库,用于处理JSON(JavaScript Object Notation)数据格式。 //ObjectMapper提供了丰富的方法来进行序列化和反序列化操作。
对于大型请求体,应该考虑使用流式处理来避免内存溢出。此外,在处理完请求体后,应该关闭Reader或InputStream以释放资源。
在现代Web框架(如Spring MVC)中,框架通常会自动处理请求体的解析,并将请求体映射到方法参数上,这使得手动处理请求体变得不那么常见。然而,了解如何在Servlet中手动处理请求体仍然是有价值的,因为它提供了对底层HTTP交互的更深入理解。
4)获取请求参数
请求参数:如登录时的用户名、密码
请求数据:包含请求行、请求头和请求体的所有数据
关系:请求参数是请求数据中的部分内容(GET请求的请求参数在请求行中;POST请求的请求参数一般在请求体中)
- getParameter(String name)获取指定名称的请求参数的值
应用举例:获取username=zs&password=123 :
@WebServlet("/req2")
public class RequestDemo2 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String username = req.getParameter("username");String password = req.getParameter("password");System.out.println(username);System.out.println(password);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {}
}
- getParameterValues(String name):获取指定名称的请求参数的所有值(当参数有多个值时)
应用举例:获取hobby=xx&hobby=game
@WebServlet("/req2")
public class RequestDemo2 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("------------");String[] hobbies = req.getParameterValues("hobby");for (String hobby : hobbies) {System.out.println(hobby);}}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {}
}
- getParameterMap():获取所有参数的map集合
应用举例:
@WebServlet("/req2")
public class RequestDemo2 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//GET请求逻辑System.out.println("get....");//1. 获取所有参数的Map集合Map<String, String[]> map = req.getParameterMap();for (String key : map.keySet()) {// username:zhangsan lisiSystem.out.print(key+":");//获取值String[] values = map.get(key);for (String value : values) {System.out.print(value + " ");}System.out.println();}}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {}
}
5)设置编码
解决POST请求方式的乱码:
- request.setCharacterEncoding("UTF-8");
GET请求方式在Tomcat 8.0版本后不会出现乱码
应用举例:
@WebServlet("/req2")
public class RequestDemo2 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//1. 解决乱码: POST getReader()//设置字符输入流的编码,设置的字符集要和页面保持一致request.setCharacterEncoding("UTF-8");//2. 获取usernameString username = request.getParameter("username");System.out.println(username);}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doGet(request, response);}
}
4、请求转发(forward)
一种在服务器内部的资源跳转方式。
浏览器发送请求给服务器,服务器中的资源A接收到请求并将请求发给资源B,资源B处理完后将结果响应给浏览器。其中,请求从资源A到资源B的过程就叫请求转发。可以转发到Servlet或JSP。
请求转发是一种服务器的行为,当客户端请求到达后,服务器进行转发,此时会将请求对象进行保 存,地址栏中的 URL 地址不会改变,得到响应后,服务器端再将响应发送给客户端,从始至终只有一个请求发出。只能转发到当前服务器的内部资源,不能从一个服务器通过转发访问另一台服务器,因此不能请求转发到服务器外部资源。
实现方式:
- req.getRequestDispatcher("资源B路径").forward(req,resp);
应用举例:
步骤一:需要创建2个servlet
@WebServlet("/req1")
public class RequestDemo1 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println("这是demo1");}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doGet(request, response);}
}
@WebServlet("/req2")
public class RequestDemo2 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println("这是demo2");}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doGet(request, response);}
}
步骤二:请求转发:在RequestDemo1的doGet方法中进行
@WebServlet("/req")
public class RequestDemo5 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println("这是demo1");//请求转发request.getRequestDispatcher("/req2").forward(request,response);}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doGet(request, response);}
}
启动访问:http://localhost:8080/request-demo/req1
看到控制台打印:
这是demo1
这是demo2
说明请求已经转发到了 /req2
5、共享数据
把请求从/req1 转发到/req2的时候,怎样传递数据给/req2 ?
使用Request对象进行请求转发资源间的共享数据。
Request对象是一个域(范围)对象,具有特定的作用范围,即在一次请求及其转发的过程中。它提供了一组方法—setAttribute、getAttribute和removeAttribute,用于存储、获取和移除数据。
应用举例:
步骤一:在源Servlet中设置数据到Request对象:
@WebServlet("/sourceServlet")
public class SourceServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 设置数据到Request对象 request.setAttribute("sharedData", "data"); // 请求转发到目标Servlet RequestDispatcher dispatcher = request.getRequestDispatcher("/targetServlet"); dispatcher.forward(request, response); }
}
步骤二:在目标Servlet中获取数据:
@WebServlet("/targetServlet")
public class TargetServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 获取共享数据 String sharedData = (String) request.getAttribute("sharedData"); // 使用共享数据System.out.println("收到分享的数据: " + sharedData);
}
这里面有两个Servlet,当访问SourceServlet时,它会将数据"data"添加到Request对象中,并通过RequestDispatcher将请求转发到TargetServlet。
在TargetServlet中,通过调用request.getAttribute("sharedData")得到之前设置的数据,并可以在该Servlet的业务逻辑中使用这些数据。
客户端的请求URL应该指向源Servlet(在这个例子中是/sourceServlet),然后由源Servlet负责转发请求并共享数据。如http://localhost:8080/request-demo/sourceServlet。
使用请求转发时,客户端访问的URL是源Servlet的URL。请求转发是一种在服务器内部将请求从一个Servlet或JSP转发到另一个Servlet或JSP的技术,客户端并不知道这个过程。