一、Request 对象和 Response 对象原理
request和response对象是由服务器创建的,供我们使用的。
request对象是来获取请求消息,response对象是来设置响应消息。
原理示意图:
二、Request 类继承体系结构
三、HttpServletRequest 接口
每次只要有请求进入 Tomcat 服务器,Tomcat 服务器就会把请求过来的 HTTP 协议信息解析好到 Request 对象中,每次请求都创建一个 Request 对象,请求完成后该对象就销毁了。
然后传递到 service 方法(doGet 和 doPost)中供我们使用,通过 HttpServletRequest 对象,课获取到所有请求信息。
四、HttpServletRequest 功能
1、常用方法
getRequestURI() 获取请求的资源路径
getRequestURL() 获取请求的统一资源定位符(绝对路径)
getRemoteHost() 获取客户端的 ip 地址
getHeader() 获取请求头
getParameter(String name) 获取请求的参数
getParameterValues(String name) 获取请求的参数(多个值的时候使用)
getParameterNames() 获取所有请求的参数名称(相当于Iterator)
getParameterMap() 获取所有参数的 map 集合,可以根据键(参数名)获取值(参数值)
getMethod() 获取请求的方式 GET 或 POST
setAttribute(key, value); 设置域数据
getAttribute(key); 获取域数据
getRequestDispatcher() 获取请求转发对象
2、获取请求信息
(1)获取请求行数据
常用方法:
(1)String getMethod() : 获取请求方式
(2)String getContextPath(): 获取虚拟目录[重要]
(3)String getServletPath(): 获取 servlet 路径
(4)String getQueryString(): 获取get方式请求参数
(5)String getRequestURI(): 获取请求URI[重要]
(6)StringBuffer getRequestURL():获取请求的URL
(7)String getProtocol(): 获取协议及版本
(8)String getRemoteAddr(): 获取客户端的IP地址
(9)String getRemoteHost(): 获取客户端的主机名
注意:URI:统一资源标识符;URL:统一资源定位符;两者区别:URI 与 URL
Demo:
1 请求行数据 GET /servletDemo/demo1?name=zhangsan HTTP/1.1
2 String getMethod(): 获取到 GET
3 String getContextPath(): 获取到 /servletDemo
4 String getServletPath(): 获取到 /demo1
5 String getQueryString(): 获取到 name=zhangsan
6 String getRequestURI(): 获取到 /servletDemo/demo1
7 StringBuffer getRequestURL():获取到 http://localhost/servletDemo/demo1
8 String getProtocol(): 获取到 HTTP/1.1
9 String getRemoteAddr(): 获取到 请求机器的IP地址
(2)获取请求头数据
String getHeader(String name): 通过请求头的名称获取请求头的值[重要]
Enumeration<String> getHeaderNames():获取所有的请求头名称
(3)获取请求体数据
请求体:只有POST请求方式,才有请求体,在请求体重封装了POST请求的请求参数
步骤:
① 获取流对象
BufferedReader getReader(): 获取字符输入流,只能操作字符数据
ServletInputStream getInputStream():获取字节输入流,可以操作所有类型数据
② 从流对象中获取数据
1 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
2 //1.获取字符流
3 BufferedReader br = request.getReader();
4
5 //2.读取数据
6 String line = null;
7 while((line = br.readLine()) != null) {
8 System.out.println(line); // 请求参数username=zs&password=abc
9 }
10 }
HttpServletRequest 类里面封装了请求的信息,可以获取请求报文里面的信息
1 @Override
2 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
3 //1.getRequestURI() 获取请求的资源路径
4 System.out.println("URI => " + request.getRequestURI());
5
6 //2.getRequestURL() 获取请求的统一资源定位符(绝对路径)
7 System.out.println("URL => " + request.getRequestURL());
8
9 //3.getRemoteHost() 获取客户端的 ip 地址
10 /**
11 * 在 IDEA 中, 使用 localhost 访问时, 得到的客户端 ip 地址是 ===>>> 127.0.0.1<br/>
12 * 在 IDEA 中, 使用 127.0.0.1 访问时, 得到的客户端 ip 地址是 ===>>> 127.0.0.1<br/>
13 * 在 IDEA 中, 使用 真实 ip 访问时, 得到的客户端 ip 地址是 ===>>> 真实的客户端 ip 地址<br/>
14 */
15 System.out.println("客户端 ip 地址 => " + request.getRemoteHost());
16
17 //4.getHeader() 获取请求头
18 System.out.println("请求头 User-Agent ==>> " + request.getHeader("User-Agent"));
19
20 //5.getMethod() 获取请求的方式 GET 或 POST
21 System.out.println( "请求的方式 ==>> " + request.getMethod() );
22 }
运行结果:
3、获取请求参数
表单数据:
1 <form action="http://localhost:8080/servlet07/parameterServlet" method="get">
2 用户名: <input type="text" name="username"><br/>
3 密码: <input type="password" name="password"><br/>
4 兴趣爱好: <input type="checkbox" name="hobby" value="cpp">C++
5 <input type="checkbox" name="hobby" value="java">Java
6 <input type="checkbox" name="hobby" value="js">JavaScript<br/>
7 <input type="submit">
8 </form>
获取表单数据:
1 @Override
2 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
3 System.out.println("-------------doGet------------");
4
5 // 获取请求参数
6 String username = req.getParameter("username");
7
8 String password = req.getParameter("password");
9 String[] hobby = req.getParameterValues("hobby");
10
11 System.out.println("用户名:" + username);
12 System.out.println("密码:" + password);
13 System.out.println("兴趣爱好:" + Arrays.asList(hobby));
14
15 //获取所有的请求里的参数名
16 Enumeration<String> names = req.getParameterNames();
17 while(names.hasMoreElements()) {
18 System.out.println(names.nextElement());
19 }
20
21 System.out.println("----------------------------");
22 Map<String, String[]> parameterMap = req.getParameterMap();
23 Set<String> key = parameterMap.keySet();
24 for (String s : key) {
25 System.out.println(s);
26 }
27 Collection<String[]> values = parameterMap.values();
28 for (String[] value : values) {
29 System.out.println("value = " + value);
30 }
31
32
33 Set<Map.Entry<String, String[]>> entries = parameterMap.entrySet();
34 Iterator<Map.Entry<String, String[]>> iterator = entries.iterator();
35 while (iterator.hasNext()) {
36 Map.Entry<String, String[]> entry = iterator.next();
37 System.out.println(entry.getKey());
38 System.out.println(entry.getValue().toString());
39 }
40
41 }
运行结果:
其中的 getParameterValues() 是获取一个数组,用于获取多个值的时候使用。
【留坑:get 与 post 的中文乱码问题】
4、请求的转发
什么是请求的转发?
请求转发是指, 服务器收到请求后, 从一次资源跳转到另一个资源的操作叫请求转发。
注意:这是一种在服务器内部的资源跳转方式,无法跳转到外部的资源。
实现步骤:
① 通过 request 对象获取请求转发器对象:
RequestDispatcher getRequestDispatcher(String path): 获取请求转发器对象,path为转发到的路径
② 使用 RequestDispatcher 对象来进行转发:
forward(ServletRequest request, ServletResponse response):转发方法
特点:
① 浏览器地址栏路径不会发生变化;
② 只能转发到自己工程的内部资源;
③ 转发是同一次请求,可以共享 Request 域中的数据;
④ 可以转发到 WEB-INF 目录下;
注意:
① 从外部(浏览器)无法直接访问 WEB-INF 目录下的资源,但是可以通过请求转发访问到;
② 执行完跳转的 servlet 的业务后,然后再回来继续执行原来的 servlet 的业务。
原理图:
Demo:
Servlet1:
1 @Override
2 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
3
4 // 获取请求的参数(办事的材料)查看
5 String username = req.getParameter("username");
6 System.out.println("在Servlet1(柜台1)中查看参数(材料):" + username);
7
8 // 给材料 盖一个章,并传递到Servlet2(柜台 2)去查看
9 req.setAttribute("key1","柜台1的章");
10
11 // 问路:Servlet2(柜台 2)怎么走
12 /**
13 * 请求转发必须要以斜杠打头,/ 斜杠表示地址为:http://ip:port/工程名/ , 映射到IDEA代码的web目录<br/>
14 *
15 */
16 RequestDispatcher requestDispatcher = req.getRequestDispatcher("/servlet2");
17 //RequestDispatcher requestDispatcher = req.getRequestDispatcher("http://www.baidu.com"); 不能跳转到服务器外的资源
18
19 // 走向Sevlet2(柜台 2)
20 requestDispatcher.forward(req,resp);
21
22 System.out.println("业务结束");
23
24 }
Servlet2:
1 @Override
2 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
3 // 获取请求的参数(办事的材料)查看
4 String username = req.getParameter("username");
5 System.out.println("在Servlet2(柜台2)中查看参数(材料):" + username);
6
7 // 查看 柜台1 是否有盖章
8 Object key1 = req.getAttribute("key1");
9 System.out.println("柜台1是否有章:" + key1);
10
11 // 处理自己的业务
12 System.out.println("Servlet2 处理自己的业务 ");
13 }
5、作为域对象存取数据
域对象:一个有作用范围的对象,可以在范围内共享数据;
Request 域:代表一次请求的范围,一般用于请求转发的多个资源中共享数据;
常用方法:
void setAttribute(String name,Object obj):存储数据到request中
Object getAttitude(String name):通过键获取值
void removeAttribute(String name):通过键移除键值对
6、获取 ServletContext 对象
request 通过 getServletContext() 方法获取 ServletContext 对象:
ServletContext servletContext = request.getServletContext();通过request 对象获取 servletcontext 对象
五、doGet 与 doPost 的请求中文乱码
1、doGet 请求的中文乱码解决
// 获取请求参数
String username = req.getParameter("username");
//1 先以 iso8859-1 进行编码
//2 再以 utf-8 进行解码
username = new String(username.getBytes("iso-8859-1"), "UTF-8");
2、POST 请求的中文乱码解决
1 @Override
2 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws Exception {
3 // 设置请求体的字符集为 UTF-8, 从而解决 post 请求的中文乱码问题
4 req.setCharacterEncoding("UTF-8");
5 System.out.println("-------------doPost------------");
6 // 获取请求参数
7 String username = req.getParameter("username");
8 String password = req.getParameter("password");
9 String[] hobby = req.getParameterValues("hobby");
10 System.out.println("用户名: " + username);
11 System.out.println("密码: " + password);
12 System.out.println("兴趣爱好: " + Arrays.asList(hobby));
13 }
注意:
① get方式:Tomcat 8 已经将 get 方式乱码问题解决了
② post 方式:获取中文会产生乱码
解决方式:在获取参数前,设置 request 的编码与页面编码一致即可
request.setCharacterEncoding("utf-8");
六、
七、
八、