请求
请求对象介绍
请求:获取资源。在BS架构中,就是客户端浏览器向服务器发出询问
请求对象:就是在项目当中用于发送请求的对象
ServletRequest 和 HttpServletRequest
请求对象的常用方法-获取各种路径
返回值 方法名 说明
String getContextPath() 获取虚拟目录名称
String getServletPath() 获取Servlet映射路径
String getRemoteAddr() 获取访问者ip地址
String getQueryString() 获取请求的消息数据
String getRequestURI() 获取统一资源标识符
StringBuffer getRequestURL() 获取统一资源定位符
package com.itheima.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; @WebServlet("/ServletDemo01") public class ServletDemo01 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //getContextPath() 获取虚拟目录名称 String contextPath = request.getContextPath(); System.out.println(contextPath); //getServletPath() 获取Servlet映射路径 String servletPath = request.getServletPath(); System.out.println(servletPath); //getRemoteAddr() 获取访问者ip地址 String remoteAddr = request.getRemoteAddr(); System.out.println(remoteAddr); //getQueryString() 获取请求的消息数据 (了解) String queryString = request.getQueryString(); System.out.println(queryString); //getRequestURI() 获取统一资源标识符 /request/ServletDemo01 共和国 String requestURI = request.getRequestURI(); System.out.println(requestURI); //getRequestURL() 获取统一资源定位符 http://localhost:8080/request/ServletDemo01 中华人民共和国 StringBuffer requestURL = request.getRequestURL(); System.out.println(requestURL); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
请求对象常用方法-获取请求头信息
返回值 方法名 说明
String getHeader(String name) 根据请求头名称获取一个值
Enumeration<String> getHeaders(String name) 根据请求头名称获取多个值
Enumeration<String> getHeaderNames() 根据所有请求头名称
package com.itheima.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.util.Enumeration; /* * 获取请求头信息的相关方法 * */ @WebServlet("/ServletDemo02") public class ServletDemo02 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //getHeader(String name) 根据请求头名称获取一个值 String connection = request.getHeader("connection"); System.out.println(connection); System.out.println("----------"); //getHeaders(String name) 根据请求头名称获取多个值 Enumeration<String> values = request.getHeaders("Accept-Encoding"); while(values.hasMoreElements()){ String value = values.nextElement(); System.out.println(value); } System.out.println("----------"); //getHeaderNames() 根据所有请求头名称 Enumeration<String> names = request.getHeaderNames(); while(names.hasMoreElements()){ String name = names.nextElement(); String value = request.getHeader(name); System.out.println(name+","+value); } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
2.3.3 请求对象常用方法3-获取请求参数(非常重要)
返回值 方法名 说明
String getParameter(String name) 根据名称获取数据
String[] getParameterValues(String name) 根据名称获取所有数据
Enumeration<String> getParameterNames() 获取所有名称
Map<String,String[]> getParameterMap() 获取所有参数键值对
package com.itheima.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.util.Enumeration; import java.util.Map; /* * 获取请求信息的相关方法 * */ @WebServlet("/ServletDemo03") public class ServletDemo03 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1.根据名称获取数据 getParameter() String username = request.getParameter("username"); System.out.println(username); String password = request.getParameter("password"); System.out.println(password); System.out.println("----------------------"); //2.根据名称获取所有数据 getParameterValues() String[] hobbies = request.getParameterValues("hobby"); for (String hobby : hobbies) { System.out.println(hobby); } System.out.println("----------------------"); //3.获取所有名称 getParameterNames() Enumeration<String> names = request.getParameterNames(); while(names.hasMoreElements()){ String name = names.nextElement(); System.out.println(name); } System.out.println("----------------------"); //4.获取所有参数的键值对 getParameterMap() Map<String, String[]> map = request.getParameterMap(); for (String key : map.keySet()) { String[] values = map.get(key); System.out.print(key+":"); for (String value : values) { System.out.print(value+" "); } System.out.println(); } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
第一种:最简单直接的封装方式
bean/Student
package com.itheima.bean; import java.util.Arrays; public class Student { private String username; private String password; private String[] hobby; public Student() { } public Student(String username, String password, String[] hobby) { this.username = username; this.password = password; this.hobby = hobby; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String[] getHobby() { return hobby; } public void setHobby(String[] hobby) { this.hobby = hobby; } @Override public String toString() { return "Student{" + "username='" + username + '\'' + ", password='" + password + '\'' + ", hobby=" + Arrays.toString(hobby) + '}'; } }
ServletDemo04:
package com.itheima.servlet; import com.itheima.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.IOException; import java.util.Enumeration; import java.util.Map; /* * 封装对象-手动封装 * */ @WebServlet("/ServletDemo04") public class ServletDemo04 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1.获取所有的数据 String username = request.getParameter("username"); String password = request.getParameter("password"); String[] hobbies = request.getParameterValues("hobby"); //2.封装学生对象 Student stu=new Student(username,password,hobbies); //输出对象 System.out.println(stu); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
第二种:使用反射方式封装
package com.itheima.servlet; import com.itheima.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.beans.IntrospectionException; import java.beans.PropertyDescriptor; import java.io.IOException; import java.lang.reflect.Method; import java.util.Map; /* * 封装对象-反射方式 * */ @WebServlet("/ServletDemo05") public class ServletDemo05 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1.获取所有的数据 Map<String, String[]> map = request.getParameterMap(); //2.封装学生对象 Student stu=new Student(); //2.1.遍历集合 for (String name : map.keySet()) { String[] value = map.get(name); //2.2获取Student对象的属性描述器,根据名称拿到 stu里面的get/set方法 try { PropertyDescriptor pd=new PropertyDescriptor(name,stu.getClass()); //2.3获取对应的setXXX方法 Method writeMethod = pd.getWriteMethod(); //2.4执行方法 if (value.length >1) { writeMethod.invoke(stu,(Object) value); }else{ writeMethod.invoke(stu,value); } } catch (Exception e) { e.printStackTrace(); } } //输出对象 System.out.println(stu); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
当我们写完此种封装方式之后,同学们可以发现,我们绝大多数封装都可以使用这段代码来实现。并且,无论是谁来写这段通用的封装代码,其代码内容都是大同小异的。那么,我们就可以得出一个很有趣的结论:一般遇到这种情况时,肯定有人帮我们写好了,我们只需要用就行了。我们后面还会遇到类似这样的情况。
此时,帮我们写好这段封装代码的是apache软件基金会,我们前面学习的tomcat也是它提供的。它里面有一个开源工具包集合commons,里面有很多开源工具类,今天我们就来讲解第一个:commons-beanutils。
第三种:使用工具类封装方式
导入这两个包
package com.itheima.servlet; import com.itheima.bean.Student; import org.apache.commons.beanutils.BeanUtils; 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.beans.PropertyDescriptor; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Map; /* * 封装对象-工具类方式 * */ @WebServlet("/ServletDemo06") public class ServletDemo06 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1.获取所有的数据 Map<String, String[]> map = request.getParameterMap(); //2.封装学生对象 Student stu=new Student(); try { BeanUtils.populate(stu,map); } catch (Exception e) { e.printStackTrace(); } //输出对象 System.out.println(stu); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
通过流对象获取请求信息
返回值 方法名 说明
BufferReader getReader() 获取字符输入流
ServletInputStream getInputStream() 获取字节输入流
package com.itheima.servlet; import com.itheima.bean.Student; import org.apache.commons.beanutils.BeanUtils; 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("/ServletDemo07") public class ServletDemo07 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //字符流(必须是post方式) /* BufferedReader br = request.getReader(); String line; while((line=br.readLine())!=null){ System.out.println(line); }*/ //br.close(); //字节流 ServletInputStream is = request.getInputStream(); byte[] arr=new byte[1024]; int len; while((len= is.read(arr))!=-1){ System.out.println(new String(arr,0,len)); } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
2.3.5请求正文中中文编码问题
关于请求中文乱码问题,我们需要分开讨论,第一是POST请求方式,第二是GET方式。
1)POST方式请求
在POST方式请求中,我们的乱码问题可以用如下代码解决:
request.setCharacterEncoding("UTF-8");
GET方式请求的正文是在地址栏中,在Tomcat8.5版本及以后,Tomcat服务器已经帮我们解决了,所以不会有乱码问题了。
而如果我们使用的不是Tomcat服务器,或者Tomcat的版本是8.5以前,那么GET方式仍然会有乱码问题,解决方式如下:(以下代码了解即可,因为我们现在使用的是Tomcat9.0.27版本)
/** * 在Servlet的doGet方法中添加如下代码 */ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { /* * GET方式:正文在地址栏 * username=%D5%C5%C8%FD * %D5%C5%C8%FD是已经被编过一次码了 * * 解决办法: * 使用正确的码表对已经编过码的数据进行解码。 * 就是把取出的内容转成一个字节数组,但是要使用正确的码表。(ISO-8859-1) * 再使用正确的码表进行编码 * 把字节数组再转成一个字符串,需要使用正确的码表,是看浏览器当时用的是什么码表 */ String username = request.getParameter("username"); byte[] by = username.getBytes("ISO-8859-1"); username = new String(by,"GBK"); //输出到浏览器:注意响应的乱码问题已经解决了 response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); out.write(username); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); }
请求对象
请求域(request域):可以在一次请求范围内进行共享数据
请求对象操作共享数据方法
返回值 方法名 说明
void setAttribute(String name,Object value) 向请求域对象中存储数据
Object getAttribute(String name) 通过名称获取请求域对象中的数据
void removeAttribute(String name) 通过名称一处请求域对象中的数据
2.3.6 请求转发(与重定向的区别)
在实际开发中,重定向和请求转发都是我们要用到的响应方式,那么他们有什么区别呢?我们通过下面的示例来看一下:
请求转发:客户端的一次请求到达后,发现需要借助其他Servlet来实现功能
特点:
- 浏览器地址栏不变
- 域对象中的数据不丢失
- 负责转发的Servlet转发前后的相应正文会丢失
- 有转发的目的地来响应客户端
返回值 方法名 说明
RequestDispatcher getRequestDispatcher(String name) 获取请求调度对象
返回值 方法名 说明
void forward(ServletRequest req,ServletResponse resp) 实现转发
ServletDemo09
package com.itheima.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; /* * 请求转发 * */ @WebServlet("/ServletDemo09") public class ServletDemo09 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); //设置共享数据 request.setAttribute("encoding","gbk"); //获取请求调度对象 request.getRequestDispatcher("/ServletDemo10").forward(request,response); } }
ServletDemo10
package com.itheima.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; /* * 请求转发 * */ @WebServlet("/ServletDemo10") public class ServletDemo10 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //获取共享数据 Object encoding = request.getAttribute("encoding"); System.out.println(encoding); System.out.println("ServletDemo10执行了"); } }
2.3.7 请求包含
在实际开发中,我们可能需要把两个Servlet的内容合并到一起来响应浏览器,而同学们都知道HTTP协议的特点是一请求,一响应的方式。所以绝对不可能出现有两个Servlet同时响应方式。那么我们就需要用到请求包含,把两个Servlet的响应内容合并输出。我们看具体使用示例:
请求包含:可以合并其他Servlet中的功能一起响应给客户端
返回值 方法名 说明
RequestDispatcher getRequestDispatcher(String name) 获取请求调度对象
返回值 方法名 说明
void include(ServletRequest req,ServletReponse resp) 实现包含
ServletDemo13
package com.itheima.servlet; import javax.servlet.RequestDispatcher; 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; /* 请求包含 */ //@WebServlet(name = "ServletDemo09",urlPatterns = "/ServletDemo09") @WebServlet("/ServletDemo13") public class ServletDemo13 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("ServletDemo13执行了"); //获取请求的调度对象 req.getRequestDispatcher("/ServletDemo14").include(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req,resp); } }
ServletDemo14
package com.itheima.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; /* 请求包含 */ //@WebServlet(name = "ServletDemo09",urlPatterns = "/ServletDemo09") @WebServlet("/ServletDemo14") public class ServletDemo14 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("ServletDemo14执行了"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req,resp); } }