Servlet学习2 -- Request对象
一.Servlet中处理请求的方式
之前介绍过Servlet的体系结构,广义上来说,Servlet是一个接口,有实现类GenericsServlet,而GenericsServlet是一个抽象类,有直接的子类HttpServlet。
而HttpServlet要比GenericsServlet要强大,因为它是由GenericsServlet抽象类扩展而来的,并且现在大部分的应用程序都是与HTTP结合起来使用,而且HTTPServlet封装了许多,使得我们的开发变得更加简洁。
之前当我们要实现Servlet接口时,是需要重写5个方法的:init,destroy,service,getServletConfig,getServletInfo,这样太麻烦,我们可以直接继承HttpServlet类,因为HTTPServlet默认已经实现了Servlet接口中的所有方法了,写代码时只需要重写需要的方法即可。
具体操作方式为:
- 继承HttpServlet
- 重写doGet()和doPost()方法,并且在doGet()或者doPost()中写入一句
this.doPost(req,resp)
或this.doGet(req,resp)
,因为这样子无论是Get请求还是POST请求,处理的方式都相同。
二.Request对象
-
request对象的原理
- request对象是由服务器创建的,我们只需要直接使用就好了。
- request对象就是将浏览器的请求封装成的对象,能够获取请求文本中的所有内容,包括请求头,请求体和请求行
-
request对象的继承体系
ServletRequest -- 接口
| 继承
HttpServletRequest -- 接口
| 实现
org.apache.catalina.connector.RequestFacade 类(tomcat) -
request对象的功能
-
获取请求行数据
-
获取请求方式
String getMethod()
-
获取虚拟目录
String getContextPath()
-
获取Servlet路径
String getServletPath()
-
获取get方式请求参数
String getQueryString()
-
获取请求URI
String getRequestURI()
String getRequestURL()
-
获取协议和版本
String getProtocol()
-
获取客户机的IP地址
String getRemoteAddr()
@WebServlet("/RequestServlet") public class RequestServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1. 获取请求方式 String method = request.getMethod(); System.out.println("请求方式为:" + method); // 2. 获取虚拟目录 String contextPath = request.getContextPath(); System.out.println("虚拟目录是:" + contextPath); // 3. 获取Servlet路径 String servletPath = request.getServletPath(); System.out.println("Servlet路径为:" + servletPath); // 4. 获取get请求参数 String queryString = request.getQueryString(); System.out.println("Get请求参数:" + queryString); // 5. 获取请求URI String requestURI = request.getRequestURI(); StringBuffer requestURL = request.getRequestURL(); System.out.println("请求URI为:" + requestURI); System.out.println("请求URL为:" + requestURL); // 6. 获取协议和版本 String protocol = request.getProtocol(); System.out.println("协议和版本为:" + protocol); // 7. 获取客户机的IP地址 String remoteAddr = request.getRemoteAddr(); System.out.println("客户机IP地址为:" + remoteAddr); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
浏览器请求为:http://localhost/BlogTest/RequestServlet?name=zhangsan&age=18 控制台输出为: 请求方式为:GET 虚拟目录是:/BlogTest Servlet路径为:/RequestServlet Get请求参数:name=zhangsan&age=18 请求URI为:/BlogTest/RequestServlet 请求URL为:http://localhost/BlogTest/RequestServlet 协议和版本为:HTTP/1.1 客户机IP地址为:0:0:0:0:0:0:0:1
-
-
获取请求头数据
String getHeader(String name)
:通过请求头名字获取请求头的值Enumeration<String> getHeaderNames()
:获取所有请求头的名字
@WebServlet("/RequestServlet2") public class RequestServlet2 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1. 获取请求头 -- 获取User-Agent的值,获知浏览器版本信息 String header = request.getHeader("User-Agent"); System.out.println("请求头User-Agent:" + header); // 2. 获取所有的请求头 Enumeration<String> headerNames = request.getHeaderNames(); System.out.println("所有请求头列表:"); while (headerNames.hasMoreElements()) { String name = headerNames.nextElement(); // 获取请求头数据 String head = request.getHeader(name); System.out.println(name + ":" + head); } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
请求头User-Agent:Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36 所有请求头列表: host:localhost connection:keep-alive cache-control:max-age=0 upgrade-insecure-requests:1 user-agent:Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36 accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3 accept-encoding:gzip, deflate, br accept-language:zh-CN,zh;q=0.9,en;q=0.8 cookie:JSESSIONID=2BFDB4BDC8DF9089DEE0BAA90B9EF721; Idea-6b401060=b4304026-b59a-47c6-8b46-5e6042267d2c
-
获取请求体数据
请求体只有POST请求才有,封装了post请求的请求参数。
获取请求体数据的操作步骤为:
-
获取流对象
BufferedReader getReader()
:获取字符输入流,只能操作字符数据ServletInputStream getInputStream()
:获取字节输入流,可以操作所有数据类型 -
从流对象中获取数据
@WebServlet("/RequestServlet3") public class RequestServlet3 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 字节流 // ServletInputStream inputStream = request.getInputStream(); // // byte[] bytes = new byte[1024]; // int len = 0; // while ((len = inputStream.read(bytes)) != -1) { // System.out.println(new String(bytes,0, len)); // } // 输出:username=zhangsan&password=12345678 // 字符流 BufferedReader reader = request.getReader(); String line = null; while ((line = reader.readLine()) != null) { System.out.println(line); } // 输出:username=zhangsan&password=12345678 } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
-
-
-
request对象其他功能
-
通用的获取请求参数
由上面的可以看出,get方式获取请求参数使用的是
getQueryString()
,post方式是通过获取请求体来得到请求参数,这样子太麻烦,还要区分,所以有以下几个方法,不论是get还是post都可以使用来获取请求参数,属于通用的。String getParameter(String name)
:根据参数名获取参数值String[] getParameterValues(String name)
:根据参数名获取参数值的数组(对于一些同一个名字有多个值的情况,比如复选框checkbox)Enumeration<String> getParameterNames()
:获取所有请求参数的名称Map<String,String[]> getParameterMap()
:获取所有参数的名称和值的Map集合
@WebServlet("/RequestServlet4") public class RequestServlet4 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1. 获取请求参数username的值 String username = request.getParameter("username"); System.out.println("username :" + username); System.out.println("--------------------"); // 2. 获取请求参数sport的所有值 String[] sports = request.getParameterValues("sport"); for (String sport : sports) { System.out.println("sport : " + sport); } System.out.println("--------------------"); // 3. 获取所有请求参数的名字 Enumeration<String> names = request.getParameterNames(); while (names.hasMoreElements()) { String name = names.nextElement(); System.out.println("name: " + name); } System.out.println("--------------------"); // 4. 获取所有请求参数的Map集合 Map<String, String[]> parameterMap = request.getParameterMap(); Set<String> keyset = parameterMap.keySet(); for (String name: keyset) { String[] values = parameterMap.get(name); for (String v : values) { System.out.println(name + " ---> " + v); } } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
请求为: http://localhost/BlogTest/RequestServlet4?username=zhangsan&&sport=basketball&&sport=football 控制台输出为: username :zhangsan -------------------- sport : basketball sport : football -------------------- name: username name: sport -------------------- username ---> zhangsan sport ---> basketball sport ---> football
-
请求转发
请求转发是在服务器内的资源跳转方式(还有一种是重定向),具有以下特点:
- 浏览器的地址栏路径是不会发生变化的。
- 只能转发到当前服务器的内部资源。
- 转发是一次请求
操作步骤为:
- 通过request获取请求转发器对象:
RequestDispatcher getRequestDispatcher(String path)
- 使用forward方法进行转发:
forward(ServletRequest request, ServletResponse response)
-
共享数据
在进行请求转发时,请求转发是一次请求,会将request和response传递给要转发到的请求中,在这中间,两个请求间可能需要共享一些数据,这些数据只存在一次请求的范围。
主要有以下方法:
void setAttribute(String name, Object obj)
:存储数据,以键值对的方式存储Object getAttribute(String name)
:通过键获取值void removeAttribute(String name)
:移除指定的键值对
第一个Servlet:
@WebServlet("/RequestServlet5") public class RequestServlet5 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("这是RequestServlet5..."); // 设置共享数据 request.setAttribute("usernmae", "zhangsan"); // 请求转发 request.getRequestDispatcher("/RequestServlet6").forward(request, response); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
第二个Servlet:
@WebServlet("/RequestServlet6") public class RequestServlet6 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("这是RequestServlet6..."); // 获取共享数据 String username = (String)request.getAttribute("usernmae"); if (username != null) { System.out.println("共享数据是: username ---> " + username); } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
请求为:http://localhost/BlogTest/RequestServlet5 控制台输出为: 这是RequestServlet5... 这是RequestServlet6... 共享数据是: username ---> zhangsan
-
获取ServletContext(以后再详解)
ServletContext getServletContext()
-
-
中文乱码问题
-
对于get方式,在service中使用的编码和解码方式默认为:ISO-8859-1,这个编码不支持中文,所以会出现乱码,需要手动修改编码方式为UTF-8,才能解决中文乱码问题。
使用方式为:
parameter = new String(parameter.getBytes("iso8859-1"), "utf-8");
注意:tomcat 8 中get方式的中文乱码问题已经解决了,可以不用自己去手动修改。
-
对于post方式,中文请求会乱码
解决方式:在获取请求参数前,设置request的编码:
request.setCharacterEncoding("utf-8");
-