目录
[1. Tomcat请求响应](#1. Tomcat请求响应)
[2. HttpServletRequest基本功能(了解)](#2. HttpServletRequest基本功能(了解))
[2.1. HttpServletRequest的功能](#2.1. HttpServletRequest的功能)
[2.2. request获取请求头数据](#2.2. request获取请求头数据)
[2.3 request获取请求相关的其它方法](#2.3 request获取请求相关的其它方法)
[3. HttpServletRequest获取参数(精通)](#3. HttpServletRequest获取参数(精通))
[3.1. 传递参数的方式](#3.1. 传递参数的方式)
[3.2. HttpServletRequest获取参数方法](#3.2. HttpServletRequest获取参数方法)
[3.3. 单值参数的接收](#3.3. 单值参数的接收)
[3.4. 多值参数接收](#3.4. 多值参数接收)
[3.5. HttpServletRequest的获得中文乱码处理(熟练)](#3.5. HttpServletRequest的获得中文乱码处理(熟练))
[3.5.1. Post请求中文乱码](#3.5.1. Post请求中文乱码)
[3.5.2. Get请求中文乱码](#3.5.2. Get请求中文乱码)
[3.6. HttpServletRequest请求转发](#3.6. HttpServletRequest请求转发)
[3.7. request作用域](#3.7. request作用域)
[4. HttpServletResponse(熟练)](#4. HttpServletResponse(熟练))
[4.1. HttpServletResponse功能介绍](#4.1. HttpServletResponse功能介绍)
[4.2. 设置状态码和其他方法](#4.2. 设置状态码和其他方法)
[4.3. 设置响应头信息](#4.3. 设置响应头信息)
[4.4. Response中文 乱码问题](#4.4. Response中文 乱码问题)
[4.5. Response重定向](#4.5. Response重定向)
[5. 面试题:转发和重定向的区别](#5. 面试题:转发和重定向的区别)
[5.1. 处理流程:](#5.1. 处理流程:)
[5.2. 路径](#5.2. 路径)
[5.3. 其他区别](#5.3. 其他区别)
1. Tomcat请求响应
Web服务器收到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的request对象、和代表响应的response对象。request和response对象即代表请求和响应,那我们要获取客户机提交过来的数据,只需要找request对象就行了。要向客户机输出数据,只需要找response对象就行了
2. HttpServletRequest基本功能(了解)
2.1. HttpServletRequest的功能
HttpServletRequest是 Java Servlet 规范中的一个接口,用于代表客户端向服务器发送的 HTTP 请求。服务器接收到客户端的请求后,会将请求信息封装成一个HttpServletRequest对象,开发者可以通过这个对象来获取请求中的各种信息。
HttpServletRequest在JavaWeb中非常重要的一个类。它是Servlet的service()方法的参数之一!所以你必须必须要掌握它!
request的功能可以分为以下几种:
- Ø 封装了请求头数据;
- Ø 封装了请求正文数据,如果是GET请求,那么就没有正文;
- Ø request是一个域对象,可以把它当成Map来添加获取数据;
- Ø 做请求的转发(一次请求一次数据)·(重定向(两次请求,两次数据))
转发:
2.2. request获取请求头数据
String value = request.getHeader("请求头名称");
request对象可以用来获取请求头数据,当然,这些请求数据都是Tomcat封装到request中去的。我们在service()方法中可以直接来获取!
request与请求头相关的方法有:
Ø String getHeader(String name):获取指定名称的请求头;
Ø Enumeration getHeaderNames():获取所有请求头名称;
java
response.setContentType("text/html;charset=utf-8");
Enumeration names = request.getHeaderNames();
while(names.hasMoreElements()) {
String name = (String)names.nextElement();
String value = request.getHeader(name);
System.out.println(name + ": " + value);
response.getWriter().println(name + ": " + value + "<br/>");
}

2.3 request获取请求相关的其它方法
request中还提供了与请求相关的其他方法,有些方法是为了我们更加便捷的方法请求头数据而设计,有些是与请求URL相关的方法。
Ø int getContentLength():获取请求正文的字节数,GET请求没有正文,没有正文返回-1;
Ø String getContentType():获取请求类型,如果请求是GET,那么这个方法返回null;如果是POST请求,那么默认为application/x-www-form-urlencoded(理解为字符串类型),其它类型以后再学;
ØString getMethod():返回请求方法,例如:GET post delete put
Ø Locale getLocale():返回当前客户端浏览器支持的Locale。java.util.Locale表示国家和言语,这个东西在国际化中很有用;
Ø String getCharacterEncoding():获取请求编码,如果没有setCharacterEncoding(),那么返回null。表示使用ISO-8859-1编码;GBK UTF-8
Ø void setCharacterEncoding(String code):设置请求编码,只对正文有效!注意,对于GET而言,没有正文!!!所以此方法只能对POST请求中的参数有效!
Ø http://localhost:8080/hello/oneServlet?name=zhangSan
ØString getContextPath():返回上下文路径,例如:/项目名称
Ø String getQueryString():返回请求URL中的参数,例如:name=zhangSan
Ø String getRequestURI():返回请求URI路径,例如:/hello/oneServlet
Ø StringBuffer getRequestURL():返回请求URL路径,例如:http://localhost/hello/oneServlet,即返回除了参数以外的路径信息;
Ø String getServletPath():返回Servlet路径,例如:/oneServlet
Ø String getRemoteAddr():返回当前客户端的IP地址;
Ø String getRemoteHost():返回当前客户端的主机名,但这个方法的实现还是获取IP地址;
Ø int getRemotePort():返回客户端的端口号,每次请求都会变;
Ø String getSchema():返回请求协议,例如:http;
Ø String getServerName():返回主机名,例如:localhost
Ø int getServerPort():返回服务器端口号,例如:80

java
resp.setContentType("text/html;charset=utf-8");
resp.setCharacterEncoding("UTF-8");
resp.getWriter().write("请求正文的字节数:"+req.getContentLength());
resp.getWriter().write("请求类型为:"+req.getContentType());
resp.getWriter().write("请求方法为:"+req.getMethod());
resp.getWriter().write("客户端浏览器支持的Locale:"+req.getLocale());
resp.getWriter().write("请求编码:"+req.getCharacterEncoding());
resp.getWriter().write("上下文路径:"+req.getContextPath());
resp.getWriter().write("请求URL中的参数:"+req.getQueryString());
resp.getWriter().write("请求URL路径:"+req.getRequestURI());
resp.getWriter().write("请求URL路径StringBuffer版:"+req.getRequestURL());
resp.getWriter().write("servlet路径:"+req.getServletPath());
resp.getWriter().write("当前客户端的IP地址:"+req.getRemoteAddr());
resp.getWriter().write("客户端的主机号:"+req.getRemoteHost());
resp.getWriter().write("客户端的端口号:"+req.getRemotePort());
resp.getWriter().write("请求协议:"+req.getScheme());
resp.getWriter().write("主机名:"+req.getServerName());
resp.getWriter().write("服务器端口号:"+req.getServerPort());

java
resp.setContentType("text/html;charset=utf-8");
resp.setCharacterEncoding("UTF-8");
resp.getWriter().println("请求正文的字节数:"+req.getContentLength());
resp.getWriter().println("请求类型为:"+req.getContentType());
resp.getWriter().println("请求方法为:"+req.getMethod());
resp.getWriter().println("客户端浏览器支持的Locale:"+req.getLocale());
resp.getWriter().println("请求编码:"+req.getCharacterEncoding());
resp.getWriter().println("上下文路径:"+req.getContextPath());
resp.getWriter().println("请求URL中的参数:"+req.getQueryString());
resp.getWriter().println("请求URL路径:"+req.getRequestURI());
resp.getWriter().println("请求URL路径StringBuffer版:"+req.getRequestURL());
resp.getWriter().println("servlet路径:"+req.getServletPath());
resp.getWriter().println("当前客户端的IP地址:"+req.getRemoteAddr());
resp.getWriter().println("客户端的主机号:"+req.getRemoteHost());
resp.getWriter().println("客户端的端口号:"+req.getRemotePort());
resp.getWriter().println("请求协议:"+req.getScheme());
resp.getWriter().println("主机名:"+req.getServerName());
resp.getWriter().println("服务器端口号:"+req.getServerPort());

3. HttpServletRequest获取参数(精通)
3.1. 传递参数的方式
传递参数的方式:GET和POST。
GET:
Ø 地址栏中直接给出参数:http://localhost/param/ParamServlet?p1=v1&p2=v2;
Ø 超链接中给出参数:
http://localhost/param/ParamServlet?p1=v1&p2=v2">点一下
Ø 表单中给出参数:<form method="GET" action="ParamServlet">...</form>
Ø Ajax暂不介绍
POST:
Ø 表单中给出参数:<form method="POST" action="ParamServlet>...</form>
Ø Ajax暂不介绍
3.2. HttpServletRequest获取参数方法
可以使用HttpServletRequest获取客户端的请求参数,相关方法如下:
Ø String getParameter(String name):通过指定名称获取参数值;
Ø String[] getParameterValues(String name):通过指定名称获取参数值数组,有可能一个名字对应多个值,例如表单中的多个复选框使用相同的name时;
Ø Enumeration getParameterNames():获取所有参数的名字;
Ø Map getParameterMap():获取所有参数对应的Map,其中key为参数名,value为参数值。
3.3. 单值参数的接收
单值参数包括单选,单值下拉框,文本,隐藏域
无论是GET还是POST,获取参数的方法是相同的。
String s1 = request.getParameter("p1");//返回v1
String s2 = request.getParameter("p2");//返回v2
get请求:
html
<h3>get请求</h3>
<a href="demo3Servlet?username=丽丽&password=123">发送get请求</a>
注意:a标签的href跳转属性跳转路径不能加/,加了路径有错误,不是在原路径后加,是重开了一个路径。
java
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取get请求的参数
String username = request.getParameter("username");
String passsword = request.getParameter("password");
System.out.println(username+" : "+passsword);
Enumeration<String> names = request.getParameterNames();
while(names.hasMoreElements()){
String name = names.nextElement();
String value = request.getParameter(name);
System.out.println(name+":"+value);
}

post请求:
html
<h3>post请求</h3>
<form action="Req3" method="post">
<input type="text" name="a"/>
<input type="text" name="b"/>
<input type="submit" value="提交"/>
</form>
java
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String a=req.getParameter("a");
String b=req.getParameter("b");
resp.getWriter().print("a= "+a+"<br/>");
resp.getWriter().print("b= "+b+"<br/>");
Enumeration names=req.getParameterNames();
while(names.hasMoreElements()){
String name=(String) names.nextElement();
String val=req.getParameter(name);
System.out.println(name+" = "+val);
}
Map<String,String[]> map=req.getParameterMap();
Set<String> keySet=map.keySet();
for(String key:keySet){
String[] vals=map.get(key);
System.out.println(key+" :");
System.out.println(key+" :" + Arrays.toString(vals));
System.out.println();
}
}

3.4. 多值参数接收
多值参数主要就是多选checkbox
例如在注册表单中,如果让用户填写喜欢的水果,那么喜欢的水果可能就是多种。那么fruit参数就会对应多个值:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>多值参数接收</title>
</head>
<body>
<form action="Req4" method="post">
<input type="checkbox" name="fruit" value="apple"/>
<input type="checkbox" name="fruit" value="banana"/>
<input type="checkbox" name="fruit" value="strawberry"/>
<input type="submit" value="提交"/>
</form>
</body>
</html>
java
package cn.tx.response;
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.Arrays;
@WebServlet(name = "Req4",urlPatterns = "/Req4")
public class RequestDemo4 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String[] fruits=req.getParameterValues("fruit");
System.out.println(Arrays.toString(fruits));
}
}



java
Map<String, String[]> map = request.getParameterMap();
Set<String> keySet = map.keySet();
for(String key : keySet){
String[] vals = map.get(key);
System.out.println(key+" :" + Arrays.toString(vals));
}
3.5. HttpServletRequest的获得中文乱码处理(熟练)
Request接收参数时有get和post两种请求方式,但是处理中文的编码却不一样,我们在做项目时会全站都采用统一的编码,最常用的就是UTF-8,在UTF-8编码的项目中的乱码处理方法如下:
3.5.1. Post请求中文乱码
我们知道,请求信息中,只有POST存在正文,所谓POST参数编码就是请求正文的编码。默认情况下,使用getParameter()获取POST请求参数时,使用的是ISO-8859-1编码。
第一种方法,针对字符串本身进行手动转码:
java
String name = request.getParameter("name");
name = new String(name.getBytes("ISO-8859-1"),"UTF-8");
System.out.println("name:"+name);
因为在获取参数时已经被错误的编码了,但因为我们知道,乱码的两个原因:本来是使用UTF-8编码的,还错误的使用了ISO-8859-1编码。所以我们可以先使用ISO-8859-1获取字节数组,然后再使用正确的UTF-8编码得到字符串,这样就没问题了。
request的setCharacterEncodng()可以设置编码,当然这必须在调用所有的getParameter()方法之前调用request的setCharacterEncodng()方法来设置编码,这样,就不会使用ISO解读字节串了,而是使用你给定的编码来解读。
第二种方法,直接设置request的编码格式:
java
request.setCharacterEncoding("UTF-8");
String name = request.getParameter("name");
System.out.println("name:"+name);
对于每个请求,只需要调用request的setCharacterEncodng()一次 ,然后所有getParameter()都会使用这个编码来解读参数。但要注意,只对请求正文有效,即POST参数。
该方法 必须放在获取参数值之前
3.5.2. Get请求中文乱码
Get请求是将参数放在URL的queryString中进行提交,故此不存在请求体,所以上面处理post请求乱码的方法不再生效.
第一种方式,同样针对字符串进行单独解码:
java
String name = request.getParameter("name");
name = new String(name.getBytes("ISO-8859-1"),"UTF-8");
System.out.println("name:"+name);
第二种方式,通过设置服务器配置来让get请求支持中文,
例如我们使用tomcat服务器,则设置/conf/server.xml:
XML
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" URIEncoding="UTF-8"/>
一旦设置了这个属性,那么对于GET参数就直接是UTF-8编码的了。但是,元素来说,对整个Tomcat都是有效的!
不建议使用get请求传递中文参数
说明:
Tomcat8.5及以上版本,无需进行设置,即可直接支持URL传递中文;
3.6. HttpServletRequest请求转发
在Servlet中请求转发是大量要使用的,因为当我们访问一个Servlet的时候通常会执行一些后台的业务逻辑,然后跳转到一个结果页面,那么跳转到结果页面的这个过程就是请求转发,
举个例子我们做登录的功能,我们填写用户名密码,然后提交到一个负责登录的Servlet,Servlet为我们做用户名和密码的校验,如果我们都正确的话,我们就要跳转到登录的提示页面,如果错误就要跳转到登录失败的页面。
Request的请求转发也可以叫做服务器端的跳转,虽然有页面的跳转但是我们会发现地址栏是不会有变化的
java
request.getRequestDispatcher("/dispatcher.jsp").forward(request,response);
我们不但可以跳转到静态页面(后续主要讲解是动态页面我们通常会跳转到一个jsp(jsp在Servlet之后产生)的提示页面,因为我们要返回的是动态页面,所有html是不适合(后续讲解))。还可以跳转到Servlet,此时我们可以给request来设置当前域中的属性值,在该域之内(当前请求完成之前)都能获得到该属性值。
java
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
System.out.println(username);
request.setAttribute("username","lili");
request.getRequestDispatcher("/dispatcher.jsp").forward(request,response);
System.out.println("========================================");
}


3.7. request作用域
在上一讲,我们提及过ServletContext的概念,它也是一个域的对象,它的范围非常大,是指定项目所有Servlet的公共的对象,随着服务器的启动而产生,服务器的停止而销毁。--应用域对象。
那么request的也是域对象,它的作用范围小的多,它的范围只在一次请求响应范围之内,每一个线程的请求都会新产生一个HttpServletRequest和HttpServletResponse的对象。--请求域对象
4. HttpServletResponse(熟练)
HttpServletResponse也是 Java Servlet 规范中的一个接口,用于代表服务器向客户端发送的 HTTP 响应。服务器处理完客户端的请求后,会通过HttpServletResponse对象来设置响应信息,将数据和状态码等返回给客户端。
request是请求对象,而response是响应对象。
response对象用于响应client请求,向客户输出信息。
他封装了JSP产生的响应,并发送到client以响应client请求。
4.1. HttpServletResponse功能介绍
response对象的功能分为以下四种:
Ø 设置响应头信息;addHeader("reFresh", "5;URL=xxxx");
Ø 发送状态码;sendError(404);
Ø 设置响应正文;getWriter().print("fdsfdsa");
Ø 重定向:sendRedirect("path");
4.2. 设置状态码和其他方法
Ø response.setContentType("text/html;charset=utf-8"):设置响应类型为html,编码为utf-8,处理相应页面文本显示的乱码;
Ø response.setCharacterEncoding("utf-8"):如果响应类型为文本,那么就需要设置文本的编码类型,然后浏览器使用这个编码来解读文本。注意,如果没有设置contentType,那么浏览器会认为contentType为text/html,如果没设置编码,那么默认为ISO-8859-1编码。所以以上两点在使用response返回结果之前必须设置。
Ø response.setStatus(200):设置状态码;
Ø response.sendError(404, "您要查找的资源不存在"):当发送错误状态码时,Tomcat会跳转到固定的错误页面去,但可以显示错误信息。
4.3. 设置响应头信息
Ø response.setHeader("contentType", "text/html;charset=utf-8"):与setContentType()方法的功能相同。setContentType()方法属于便捷方法;
Ø 刷新(定时重定向):
Ø response.setHeader("Refresh","5; URL=http://www.baidu.com"):5秒后自动跳转到百度主页。
4.4. Response中文 乱码问题
当我们使用response向页面返回带有中文的值时,可能会出现中文乱码,需要进行如下设置:
java
response.setContentType("text/html;charset=utf-8");
response.setCharacterEncoding("UTF-8");
response.getWriter().write("张三");
4.5. Response重定向
使用response对象的sendRedirect()方法能够将网页重定向到还有一个页面。重定向支持将地址重定向到不同的主机上,这一点与转发不同。在client浏览器上将会得到跳转后的地址,并又一次发送请求链接;用户能够从浏览器的地址栏中看到跳转后的地址;重定向操作后,request中的属性将会所有失效,并开始一个新的request对象
html
response.sendRedirect("/param_demo/success.html");
java
package cn.tx.response;
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 = "RedpondrServlet2",urlPatterns = "/r2")
public class RedpondrServlet2 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/**
* 第一种原理方式
* 1,设置状态码 setStatus(302);
* 2,设置响应头,重定向的请求地址 setHeader(location,/success.html)
* 注意:地址的写法与请求转发不同因为重定向可以跨项目 地址两种写法1,绝对路径2,相对路径
* 第二种方法
* 重定向方式第二种自动设置状态码和头
* response.sendRedirect("/success.html");
*/
//response.setStatus(302);
//response.setHeader("location","/success.html");
//重定向方式第二种自动设置状态码和头
//response.sendRedirect("/success.html");
response.sendRedirect("http://www.taobao.com");
}
}

5. 面试题:转发和重定向的区别
5.1. 处理流程:
Ø 请求转发:
ü 客户端发送请求,Servlet做出业务逻辑处理。
ü Servlet调用forward()方法,服务器Servlet把目标资源返回给客户端浏览器。
Ø 重定向:
ü 客户端发送请求,Servlet做出业务逻辑处理。
ü Servlet调用response.sendReadirect()方法,把要访问的目标资源作为response响应头信息发给客户端浏览器。
ü 客户端浏览器重新访问服务器资源xxx.jsp,服务器再次对客户端浏览器做出响应。
5.2. 路径
Ø 使用相对路径在重定向和转发中没有区别
Ø 重定向和请求转发使用绝对路径时,根/路径代表了不同含义
ü 重定向 response.sendRedirect("xxx")是服务器向客户端发送一个请求头信息,由客户端再请求一次服务器。**/指的Tomcat的根目录,**写绝对路径应该写成"/当前Web程序根名称/资源名" 。如"/WebModule/login.jsp","/bbs/servlet/LoginServlet"
ü 转发 是在服务器内部进行的,写绝对路径/开头指的是当前的Web应用程序。绝对路径写法就是"/login.jsp"或"/servlet/LoginServlet"。
举个现实的例子:
淘宝,我们可以在淘宝里选择购物车、信息等--转发。但是想要从淘宝跳转到百度就不行了,因为不是淘宝内部的业务。只能通过输入全路径跳转--重定向。
Ø 总结:
以上要注意是区分是从服务器外的请求,还在是内部转发,从服务器外的请求,从Tomcat根写起(就是要包括当前Web的根);是服务器内部的转发,很简单了,因为在当前服务器内,/写起指的就是当前Web的根目录。
5.3. 其他区别
Ø request.getRequestDispatcher() 是容器中控制权的转向,在客户端浏览器地址栏中不会显示出转向后的地址;服务器内部转发,整个过程处于同一个请求当中。
Ø response.sendRedirect() 则是完全的跳转,浏览器将会得到跳转的地址,并重新发送请求链接 。这样,从浏览器的地址栏中可以看到跳转后的链接地址。不在同一个请求。重定向,实际上客户端会向服务器端发送两个请求。
Ø 所以转发中数据的存取可以用request作用域:request.setAttribute(), request.getAttribute(),重定向是取不到request中的数据的。只能用session。
Ø forward()更加高效,在可以满足需要时,尽量使用RequestDispatcher.forward()方法。
Ø RequestDispatcher 是通过调用HttpServletRequest对象的getRequestDispatcher()方法得到的,是属于请求对象的方法。
Ø sendRedirect() 是HttpServletResponse对象的方法,即响应对象的方法,既然调用了响应对象的方法,那就表明整个请求过程已经结束了,服务器开始向客户端返回执行的结果。
Ø 重定向可以跨域访问,而转发是在web服务器内部进行的,不能跨域访问。
Ø 同源策略(课下) ip地址不一样