1、request
1.1 什么是request
在Servlet API中,定义了一个HttpServletRequest接口,它继承自ServletRequest接口,专门用来封装HTTP请求消息。由于HTTP请求消息分为请求行、请求头和请求体三部分,因此,在HttpServletRequest接口中定义了获取请求行、请求头和请求消息体的相关方法.
Web服务器收到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的request对象、和代表响应的response对象。
request代表请求对象. 原型是HttpServletRequest, 服务器创建好的, 以形参的方式存在doGet()/doPost()方法里面
1.2 request作用
- 操作请求三部分(行,头,体)
- 请求转发
- 作为域对象存数据
HttpRequest 接口
表示一个HTTP请求消息,由方法和uri组成。
HttpRequest 常用方法
//返回请求的URI(包括查询字符串(如果有的话),但仅当它对于URI表示是格式良好的)
1、URI getURI();
//返回请求的HTTP方法
2、default HttpMethod getMethod()
//以String类型返回请求的HTTP方法
String getMethodValue()
URI
在java.net
包中
统一资源标识符(URI)的引用
URI 常用方法
//返回此URI的已解码路径
//此方法返回的字符串与getRawPath方法返回的字符串相等,只是所有转义的八位元序列都被解码
1、public String getPath()
//未被解码
public String getRawPath()
HttpMessage 接口
表示HTTP请求和响应消息的基本接口。由HttpHeaders组成,可通过getHeaders()检索
HttpMessage 常用方法
//返回此消息的头
HttpHeaders getHeaders()
HttpHeaders 类
一个表示HTTP请求或响应报头的数据结构,将String报头名称映射到String值列表
除了Map定义的常规方法外,该类还提供了许多常见的方便方法
HttpHeaders 常用方法
//返回给定头名称的第一个值(如果有的话)
public String getFirst(String headerName)
HttpCookie
将HTTP cookie表示为与“Cookie”请求头内容一致的名称-值对
HttpCookie 常用方法
//返回cookie名称
public String getName()
//返回cookie值或一个空字符串(never null)
public String getValue()
1.3 request常用方法
1 获取客户机信息(操作请求行)
请求方式 请求路径(URI) 协议版本
GET /day17Request/WEB01/register.htm?username=zs&password=123456 HTTP/1.1
- getMethod();获取请求方式
- getRemoteAddr() ;获取客户机的IP地址(知道是谁请求的)
- getContextPath(); 获得当前应用工程名(部署的路径);
- getRequestURI();获得请求地址,不带主机名
- getRequestURL();获得请求地址,带主机名
- getServerPort();获得服务端的端口
- getQueryString();获的请求参数(get请求的,URL的?后面的. eg:username=zs&password=123456)
@WebServlet("/demo01")
public class ServletDemo01 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//使用request对象获取请求行的信息:
//1. 获取请求的方式(可能会用)
String method = request.getMethod();
//System.out.println("请求方式为:" + method);
//2. 获取客户端的ip地址
String remoteAddr = request.getRemoteAddr();
//System.out.println("客户端的ip地址是:" + remoteAddr);
//3. 获取项目部署的路径(以后可能用到)
String contextPath = request.getContextPath();
//System.out.println("项目部署路径是:" + contextPath);
//4. 获取请求的url: 统一资源定位符 http://localhost:8080/requestDemo/demo01
String url = request.getRequestURL().toString();
//System.out.println("此次请求的url是:" + url);
//5. 获取请求的uri: 统一资源标识符,在url的基础上省略了服务器路径"http://loaclhost:8080"
String uri = request.getRequestURI();
System.out.println(uri);
}
}
2 获得请求头信息(操作请求头)
请求头: 浏览器告诉服务器自己的属性,配置的, 以key value存在, 可能一个key对应多个value
public String getHeader(String name)
//返回指定请求头的值。如果请求不包含指定名称的头,此方法返回null。
//如果有多个同名的头,这个方法返回请求中的第一个头。头名称不区分大小写
//User-Agent: 浏览器信息
//Referer:来自哪个网站(防盗链)
public long getDateHeader(String name)
//返回指定请求头的值。对包含日期的Header使用此方法,例如If-Modified-Since。
public Enumeration<String> getHeaders(String name)
//以String对象的枚举形式返回指定请求头的所有值
public Enumeration<String> getHeaderNames()
//返回此请求包含的所有头名称。如果请求没有头,此方法返回一个空枚举。
public int getIntHeader(String name)
//以int类型返回指定请求头的值。如果请求没有指定名称的头,该方法返回-1
3 获得请求参数
//在ServletRequest中
public String getParameter(String name)
//获得指定参数名对应的值。如果没有则返回null,如果有多个获得第一个。 例如:username=jack
//对于HTTP servlet,参数包含在查询字符串或发布的表单数据中。
public Enumeration<String> getParameterNames()
//获得指定参数名对应的所有的值。此方法专业为复选框提供的。
//例如:hobby=抽烟&hobby=喝酒&hobby=敲代码
public String[] getParameterValues(String name)
//返回含给定请求参数的所有值,如果参数不存在,则返回null。
public Map<String, String[]> getParameterMap()
//获得所有的请求参数。key为参数名,value为key对应的所有的值。
3.1 请求参数乱码处理
我们在输入一些中文数据提交给服务器的时候,服务器解析显示出来的一堆无意义的字符,就是乱码。
- get方式, 我们现在使用的tomcat>=8.0了, 乱码tomcat已经处理好了
- post方式, 就需要自己处理
怎么解决乱码: 只要在获取请求参数之前,调用request.setCharacterEncoding(UTF-8);
//在ServletRequest中
void setCharacterEncoding(String env); //设置请求体的编码
@WebServlet("/demo03")
public class ServletDemo03 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
//1. 根据参数名,获取一个参数值
String username = request.getParameter("username");
//System.out.println("获取的请求参数username=" + username);
//2. 根据参数名,获取多个参数值:比如说注册时候的兴趣爱好的复选框
String[] hobbies = request.getParameterValues("hobby");
/*for (String hobby : hobbies) {
System.out.println(hobby);
}*/
//3. 获取所有的请求参数
//getParameterMap()获取所有请求参数,请求参数的参数名就是map的key,请求参数的参数值就是map的value
Map<String, String[]> parameterMap = request.getParameterMap();
//遍历出每一个请求参数
Set<Map.Entry<String, String[]>> entries = parameterMap.entrySet();
for (Map.Entry<String, String[]> entry : entries) {
String parameterName = entry.getKey();
String[] values = entry.getValue();
for (String value : values) {
System.out.println("参数名:" + parameterName + ",参数值:" + value);
}
}
}
}
其它
public Cookie[] getCookies()
//返回一个数组,其中包含客户端在此请求中发送的所有Cookie对象。如果没有发送cookie,该方法返回null
使用BeanUtils封装
以前封装数据的时候,实体类有多少个字段,我们就需要手动编码调用多少次setXXX方法,因此,我们需要BeanUtils来解决这个问题。
BeanUtils是Apache Commons组件的成员之一,主要用于简化JavaBean封装数据的操作。
- 如果请求参数有多个需要封装到JavaBean里面, 建议先获得Map, 再使用BeanUtils封装到JavaBean对象
注意: JavaBean属性需要和Map的key一致 说白了也就是JavaBean属性需要和表单的name一致
请求转发
- 请求转发的作用:跳转页面,比如说添加完数据之后跳转到数据的展示页面,删除完数据之后跳转到展示页面
public RequestDispatcher getRequestDispatcher(String path)
//返回一个位于给定路径上的资源的包装器。RequestDispatcher对象可用于向资源转发请求或
//将资源包含在响应中。资源可以是动态的,也可以是静态的
- 请求转发的代码
request.getRequestDispatcher("转发的路径").forward(request,response);
- 请求转发的特征
- 跳转操作是由服务器执行的,所以客户端地址栏不会发生变化
- 跳转操作不会发起新的请求
- 可以跳转到WEB-INF中的资源,但是不能跳转到其它项目的资源
RequestDispatcher
RequestDispatcher常用方法
public void forward(ServletRequest request, ServletResponse response)
//将请求从servlet转发到服务器上的另一个资源(servlet、JSP文件或HTML文件)。
//该方法允许一个servlet对请求进行初步处理,并允许另一个资源生成响应。
作为域对象存取值
ServletContext: 范围 整个应用(无论多少次请求,只要是这个应用里面的都是可以共享的)
request范围: 一次请求有效 (转发可以使用)
域对象是一个容器,这种容器主要用于Servlet与Servlet/JSP之间的数据传输使用的。
public Object getAttribute(String name)
public Enumeration<String> getAttributeNames()
public void setAttribute(String name, Object o)
public void removeAttribute(String name)
/**
* request作为域对象在不同的Servlet之间进行数据的共享,它只能在同一次请求中进行数据共享
*
* request域对象只有和请求转发一起使用才有意义
*/
@WebServlet("/demo06")
public class ServletDemo06 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 目标: 在ServletDemo07中获取ServletDemo06中的变量username的值
// 要求只能是由ServletDemo06跳转到ServletDemo07的时候才能获取
String username = "周杰棍";
//将username存储到request域对象中
request.setAttribute("name",username);
//请求转发跳转到ServletDemo07
request.getRequestDispatcher("/demo07").forward(request, response);
}
}
ServletDemo07的代码
@WebServlet("/demo07")
public class ServletDemo07 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//使用request域对象中取出name的值
System.out.println("在ServletDemo07中获取username的值:"+request.getAttribute("name"));
}
}
2、Response
2.1 HttpServletResponse
在Servlet API中,定义了一个HttpServletResponse接口(doGet,doPost方法的参数),它继承自ServletResponse接口,专门用来封装HTTP响应消息。由于HTTP响应消息分为响应行、响应头、响应体三部分,因此,在HttpServletResponse接口中定义了向客户端发送响应状态码、响应头、响应体的方法
2.2作用
- 操作响应的三部分(响应行,响应头,响应体)
HttpServletResponse 常用方法
//将指定的cookie添加到响应。可以多次调用此方法来设置多个cookie
public void addCookie(Cookie cookie)
操作响应行
public void setStatus(int sc)
//设置此响应的状态码
常用的状态码:
200:成功
302:重定向
304:访问缓存
404:请求路径错误
500:服务器错误
操作响应头
响应头: 是服务器指示浏览器去做什么
一个key对应一个value
public void setDateHeader(String name, long date)
//设置具有给定名称和日期值的响应头 如果已经设置,新值将覆盖前一个值。
public void addDateHeader(String name, long date)
//添加具有给定名称和日期值的响应头 此方法允许响应头具有多个值 此方法允许响应头具有多个值。
public void setHeader(String name, String value)
//设置具有给定名称和值的响应头 如果已经设置,新值将覆盖前一个值。
public void addHeader(String name, String value)
//此方法允许响应头具有多个值。
public boolean containsHeader(String name)
//测试是否已经设置了指定的响应头
public void setIntHeader(String name, int value)
public void addIntHeader(String name, int value)
//此方法允许响应头具有多个值
一个key对应多个value
常用的响应头
Refresh: 定时跳转 (eg:服务器告诉浏览器5s之后跳转到百度)
Location:重定向地址(eg: 服务器告诉浏览器跳转到xxx)
Content-Disposition: 告诉浏览器下载
Content-Type:设置响应内容的MIME类型(服务器告诉浏览器内容的类型)
定时刷新
response.setHeader("refresh","秒数;url=跳转的路径"); //几秒之后跳转到指定的路径上
重定向
public void sendRedirect(String location)
//使用指定的重定向位置URL向客户端发送临时重定向响应
//此方法将状态码设置为SC_FOUND 302 (Found)。
- 重定向两次请求
- 重定向的地址栏路径改变
- 重定向的路径写绝对路径(带域名/ip地址的, 如果是同一个项目里面的,域名/ip地址可以省略)
- 重定向的路径可以是项目内部的,也可以是项目以外的(eg:百度)
- 重定向不能重定向到WEB-INF下的资源
- 把数据存到request里面, 重定向不可用
//方式一: 重定向
//1.设置状态码
//response.setStatus(302);
//2.设置重定向的路径(绝对路径,带域名/ip地址的,如果是同一个项目里面的,域名/ip地址可以省略)
//response.setHeader("Location","http://localhost:8080/day28/demo08");
//response.setHeader("Location","/day28/demo08");
//response.setHeader("Location","http://www.baidu.com");
//方式二: 直接调用sendRedirect方法, 内部封装了上面两行
response.sendRedirect("http://localhost:8080/day28/demo08");
重定向和请求转发的对比
重定向的特点:
- 重定向的跳转是由浏览器发起的,在这个过程中浏览器会发起两次请求
- 重定向跳转可以跳转到任意服务器的资源,但是无法跳转到WEB-INF中的资源
- 重定向跳转不能和request域对象一起使用
- 重定向跳转浏览器的地址栏中的地址会变成跳转到的路径
请求转发的特点:
-
请求转发的跳转是由服务器发起的,在这个过程中浏览器只会发起一次请求
-
请求转发只能跳转到本项目的资源,但是可以跳转到WEB-INF中的资源
-
请求转发可以和request域对象一起使用
操作响应体
//在ServletResponse中
public ServletOutputStream getOutputStream() throws IOException
//返回一个适合在响应中写入二进制数据的ServletOutputStream
public PrintWriter getWriter() throws IOException
//返回一个PrintWriter对象,该对象可以向客户端发送字符文本
//PrintWriter使用getCharacterEncoding返回的字符编码。
public String getCharacterEncoding()
//返回此响应中发送的正文所使用的字符编码(MIME字符集)的名称
//如果没有指定字符编码,则返回ISO-8859-1。
指定字符编码:
//在ServletContext中
public void setRequestCharacterEncoding(String encoding)
//在ServletResponse中显式指定
public void setCharacterEncoding(String charset)
public void setContentType(String type)
//设置发送到客户端的响应的内容类型。
//给定的内容类型可能包括一个字符编码规范,例如text/html;charset=UTF-8
//隐式指定
setLocale(java.util.Locale)
//显式规范优先于隐式规范
页面输出只能使用其中的一个流实现,两个流是互斥的.
3.1 使用字符输出流输出字符串
- 解决字符流输出中文乱码问题
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.io.PrintWriter;
/**
* response设置响应体的信息
* 直接给浏览器要展示的数据
*
* 解决响应体的乱码问题
* response.setContentType("text/html;charset=UTF-8");
* 这句代码底层做了什么?
* 1. 设置服务器响应的字符集为UTF-8
* 2. 设置Content-Type响应头的信息为 "text/html;charset=UTF-8"
* 让浏览器知道了服务器的响应字符集UTF-8,那么浏览器也会使用UTF-8解码
*/
@WebServlet("/demo04")
public class ServletDemo04 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
//要向浏览器输出响应体的信息,需要通过流来进行操作
//第一种:字符串,输出文本内容
PrintWriter writer = response.getWriter();
//使用字符流往浏览器输出文本
//1. writer()方法,只能输出字符串,如果输出int、float等等类型的话,则会有问题
writer.write("你好世界");
//2. print()方法,可以输出数字、字符串
//writer.print(8);
}
}
3.2 使用字节输出流向浏览器输出文件
目标是:向浏览器输出一张图片
注意:需要引入commons-io的jar包
@WebServlet("/demo05")
public class ServletDemo05 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1. 读取b.jpg图片,将其转换成字节输入流,使用ServletContext
ServletContext servletContext = getServletContext();
InputStream is = servletContext.getResourceAsStream("b.jpg");
//2. 使用字节输出流,将is中的字节都输出到浏览器
ServletOutputStream os = response.getOutputStream();
/*byte[] buffer = new byte[1024];
int len = 0;
while ((len = is.read(buffer)) != -1){
os.write(buffer,0,len);
}*/
IOUtils.copy(is,os);
os.close();
is.close();
}
}
IOUtils
commons-io-1.4.jar
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version> 1.3.2</version>
</dependency>
IOUtils常用方法
public static int copy(InputStream input, OutputStream output) throws IOException
//从输入流复制字节到输出流
//大的流(超过2GB)在拷贝完成后将返回一个字节拷贝值-1,
//对于大的流,使用copyLarge(InputStream, OutputStream)方法
public static long copyLarge(InputStream input, OutputStream output)
完成文件下载
创建文件下载的列表的页面,点击列表中的某些链接,下载文件.
2.1什么是文件下载
将服务器上已经存在的文件,输出到客户端浏览器.
说白了就是把服务器端的文件拷贝一份到客户端, 文件的拷贝—> 流(输入流和输出流)的拷贝
2.2文件下载的方式
-
第一种:超链接方式(不推荐)
链接的方式:直接将服务器上的文件的路径写到href属性中.如果浏览器不支持该格式文件,那么就会提示进行下载, 如果浏览器支持这个格式(eg: png, jpg…)的文件,那么直接打开,不再下载了
-
第二种:手动编码方式(推荐)
手动编写代码实现下载.无论浏览器是否识别该格式的文件,都会下载.
3.1超链接方式
- 准备下载的资源(文件)
- 编写一个下载页面
- 在这个页面上定义超链接,指定href
3.2编码方式
3.2.1手动编码方式要求
设置两个头和一个流
设置的两个头:
Content-Dispostion: 服务器告诉浏览器去下载
设置一个流:
获得要下载的文件的输入流.
代码实现
<body>
<h1>超链接方式直接下载</h1>
<a href="file/a.jpg">下载a.jpg</a><br>
<a href="file/b.jpg">下载b.jpg</a><br>
<a href="file/c.zip">下载c.zip</a><br>
<a href="file/d.jpg">下载d.jpg</a><br>
<a href="file/e.jpg">下载e.jpg</a><br>
<h1>自定义Servlet进行下载</h1>
<a href="download?fileName=a.jpg">下载a.jpg</a><br>
<a href="download?fileName=b.jpg">下载b.jpg</a><br>
<a href="download?fileName=c.zip">下载c.zip</a><br>
<a href="download?fileName=d.jpg">下载d.jpg</a><br>
<a href="download?fileName=e.jpg">下载e.jpg</a><br>
</body>
</html>
import org.apache.commons.io.IOUtils;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
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.io.InputStream;
import java.net.URLEncoder;
/**
* 1. 读取客户端想下载的文件
* 2. 将客户端想下载的文件使用字节输出流的方式响应给客户端
*/
@WebServlet("/download")
public class DownloadServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1. 获取到客户端想要下载的文件名
String fileName = request.getParameter("fileName");
//设置下载的文件的mime-type
String mimeType = getServletContext().getMimeType(fileName);
response.setHeader("Content-Type",mimeType);
//2. 使用字节输入流读取客户端要下载的那个文件
InputStream is = getServletContext().getResourceAsStream("file/" + fileName);
//3. 使用字节输出流,将图片输出到浏览器
ServletOutputStream os = response.getOutputStream();
//输出之前,我们通过设置响应头的方式,指示客户端下载文件
//我们先将fileName进行URL编码: 使用URLEncoder
String encodeFileName = URLEncoder.encode(fileName, "UTF-8");
response.setHeader("Content-Disposition","attachment;filename="+encodeFileName);
IOUtils.copy(is,os);
os.close();
is.close();
}
}
URLEncoder
HTML表单编码的实用程序类。该类包含静态方法,用于将String转换为application/x-www-form-urlencoded MIME格式。有关HTML表单编码的更多信息,请参阅HTML规范。
URLEncoder常用方法
public static String encode(String s, String enc)
//使用特定的编码方案将字符串转换为application/x-www-form-urlencoded格式。
//此方法使用提供的编码方案来获取不安全字符的字节。
//万维网联盟建议使用UTF-8