今日内容
1. HTTP协议:响应消息
2. Response对象
3. ServletContext对象
一、HTTP协议:
* 作为服务器开发人员,我们需要获取请求消息,设置发送的响应消息。
(浏览器会自动的解析这些响应消息,所以我们无需关心这些。)
1. 请求消息:客户端发送给服务器端的数据。
* 数据格式
1. 请求行
2. 请求头
3. 请求空行
4. 请求体
2. 响应消息:服务器端发送给客户端的数据。
* 数据格式
1. 响应行
1.组成: 协议/版本 响应的状态码 状态码的描述
HTTP/1.1 200 OK
200 OK
(200状态码告诉浏览器:200状态码代表OK,响应成功)
2.响应状态码:服务器告诉客户端浏览器本次请求和响应的状态
1.状态码都是3位数字
* 分类:
1. 1xx:服务器接收客户端消息,但没有接收完成,发送1xx状态码继续等
待请求消息。
2. 2xx:成功。代表:200
3. 3xx:重定向。代表:302(重定向),304(访问缓存)
4. 4xx:客户端错误。
代表404(请求路径没有对应的资源)
代表405:请求方式(GET/POST)没有对应的(doGet()/doPost())方法
5. 5xx:服务器端错误。
代表500:服务器内部出现异常。
500 – Internal Server Error
2. 响应头
1.格式: 头名称:值
2.常见的响应头:
1.Content-Type: text/html;charset=UTF-8
服务器告诉客户端浏览器本次响应体数据格式text/html以及编码格式charset
=UTF-8。
(是根据服务器中html页面里面定义的编码格式)
2.Content-Length: 99
字节个数式
3.Centent-disposition:服务器告诉客户端以什么格式打开响应体数据。
* 默认值:in-line,在当前页面内打开。
* attachment;filename=xxx:以附加形式打开响应体。(文件下载)
3. 相应空行
4. 响应体:传输的数据。
* 响应的字符串格式:
1.响应行:
HTTP/1.1 200 OK
2.响应头:
Content-Type: text/html;charset=UTF-8
Content-Length: 99
Date: Mon, 04 May 2020 05:14:15 GMT
3.响应空行:
4.响应体:html页面
```
<html>
<head>
<title>$Title$</title>
</head>
<body>
hello,response
</body>
</html>
```
二、Response对象
* 继承体系:
Interface ServletResponse
|extends
Interface HttpServletResponse
* 功能:设置响应消息。
1.设置响应行
1.格式:HTTP/1.1 200 OK
2.设置状态码:void setStatus(int sc)
2.设置响应头
1.设置头:void setHeader(String name, String value)
3.设置响应体
* 使用步骤:
1.获取输出流
* 字符输出流:PrintWriter getWriter()
* 字节输出流:ServletOutputStream getOutputStream()
2.使用输出流将数据输出到客户端浏览器。
2.2. 案例
1.完成重定向
*重定向和转发类似,也是一种资源跳转的方式。
重定向发生在:
A资源告诉浏览器,我没有满足你的资源,B资源有。
A资源告诉浏览器重定向状态码:302;
告诉B资源的路径:响应头location(B资源的路径)
* 代码
```
//访问/responseDemo1资源,会自动跳转到/responseDemo2资源。
//1.设置状态吗为302
resp.setStatus(302);
//2.设置响应头location
resp.setHeader("location", "/day0504_Response/responseDemo2");
```
* 发现除了setHeader()的第二个参数外,其他都是固定的,所以Response对象提供了
简单的重定向方式。
void sendRedirect(String location)
resp.sendRedirect("/day0504_Response/responseDemo2");
* 为了避免虚拟目录改变引起的资源丢失:动态获取虚拟目录
String contextPath = req.getContextPath();
resp.sendRedirect(contextPath+"/responseDemo2");
* 重定向(redirct)的特点:
1. 转发地址栏路径变化
2. 转发可以访问其他站点(服务器)的资源
3. 转发是两次请求
不能request对象来共享数据了。
* 转发(forward)的特点:
1. 转发地址栏路径不变
2. 转发只能访问当前服务器下的资源
3. 转发是一次请求。
意味着可以使用request对象来共享数据
* 路径的写法
1.路径的分类:
1.相对路径:通过相对路径不可以确定唯一资源
* 如:./index.html
* 不以/开头,以.开头(在当前路径下)
* 规则:确定当前资源和目标资源之间的相对位置关系。
* ./:当前资源的当前目录
* ../:当前资源的上一级目录
2.绝对路径:通过绝对路径可以确定唯一的资源
* 如:http://localhost/day0504/responseDemo1
* 简化省去协议,服务器ip域名和端口:/day0504/responseDemo1
* 可以简单的认为:以/开头的路径
* 规则:判断定义的路径是给谁用的?判断请求从哪发出
* 给客户端浏览器使用:需要加虚拟目录
一般都是从浏览器发出的请求:请求服务器的资源。
重定向也要加虚拟目录。
建议虚拟目录动态获取:request.getContextPath()。
* 给服务器使用:不需要加虚拟目录
如:转发。是在服务器内部,通过AServlet请求BServlet。是服务
器内部做的一个资源跳转,这是给服务器内部使用的。(地址栏
没有变化)
2.服务器输出字符数据到浏览器
* 步骤:
1. 获取字符输出流
PrintWriter pw = resp.getWriter();获取的流默认编码是:ISO-8859-1
2. 输出数据
* 乱码
输出数据:编码
服务器
浏览器显示:解码
字符集:默认的字符集GBK
* 解决乱码:
1.重新设置流的编码
2.告诉浏览器服务器发送的响应体使用的编码
3.在设置流之前设置。
resp.setContentType("text/html;charset=GBK");
* 详见:ResponseDemo4
3.服务器输出字节数据到浏览器
//服务器告诉浏览器:我发送的消息体编码格式是utf-8,建议浏览器也是用该编码解码
resp.setContentType("text/html;charset=utf-8");
//1.获取字节输出流
ServletOutputStream sos = resp.getOutputStream();
//2.输出数据
//sos.write("你好".getBytes());默认的是GBK
sos.write("你好".getBytes("utf-8"));
* 详见:ResponseDemo5
4.验证码
1.本质:图片
2.目的:防止恶意表单注册。
* 详见CheckCodeServlet,register.html
三、ServletContext对象
1.概念:代表整个web应用(工程),可以和应用的容器(服务器)来通信
2.获取:
1.通过request对象获取
request.getServletContext();
2.通过HttpServlet获取
HttpServlet的父类GenericServlet中的方法:getServletContext()
一般我们写的Servlet继承了HttpServlet,所以可以直接用。
this.getServletContext();
3.功能:
1.获取MIME类型
* MINE类型:在互联网通信过程中定义的一种文件数据类型
* 格式:大类型/小类型 text/html image/jpeg
* 获取:通过ServletContext中的方法:
* String getMimeType(String file)
2.域对象:共享数据的。
1. setAttribute(String name, Object value)
2. getAttribute(String name)
3. removeAttribute(String name)
* ServletContext对象域的范围:所有用户(可以看不同的的浏览器,那么就是不同用户
的请求),所有请求的数据。
* 生命周期:服务器启动创建,服务器关掉销毁。所以在内存中长时间存在。
3.获取文件的真实/运行(服务器)路径。
我们写了一个web项目,那么该项目会存在于两个地方。tomcat和本地工作空间,这
两个地方各有一份。当我们用浏览器访问这个项目,肯定是找tomcat的,尽管我们目前可
以在单机运行,但是将来这些项目一定是在远程运行的,那么就需要了解该项目真实的运
行路径。
1.方法:ServletContext中的方法
String getRealPath(String path)
每一个项目都会对应一个配置:
Using CATALINA_BASE: "C:\Users\13099\.IntelliJIdea2019.3\system\tomcat\Tomcat_8_5_31_day0504_Response"
在该目录下的Catalina\localhost\day0504_Response.xml文件中。
打开该文件:有如下内容
<Context path="/day0504_Response" docBase="E:\Idea_Project\day0504_Response\out\artifacts\day0504_Response_war_exploded" />
那么该项目真正对应的服务器路径是:
docBase="E:\Idea_Project\day0504_Response\out\artifacts\day0504_Response_war_exploded" />。
找的是工作空间里面out目录下的写内容,并没有把它copy到webapps下面。此时
我们可以找到这个目录,这个目录下的内容被发布到服务器里面了。
所以ServletContextDemo5得到的b.txt的真实路劲:
E:\Idea_Project\day0504_Response\out\artifacts\day0504_Response_war_exploded\b.txt
* 详见ServletContextDemo5
四、案例
* 文件下载需求:
1. 页面显示超链接
2. 点击超链接后弹出下载提示框
3. 完成图片文件下载
* 分析
1.浏览器默认超链接指向的资源如果能够被浏览器解析,则在浏览器中展示,如果不能,
则弹出下载提示框。
2.任何资源都必须弹出下载提示框。
3.使用响应头设置资源的打开方式:以附件的形式打开
* content-disposition:attachment;filename=xxx
* 步骤:
1.定义页面,编辑超链接href属性值,指向Servlet,传递请求参数:资源名称filename
2.定义Servlet
1.获取文件的名称
2.使用字节输入流加载文件进内存
3.指定response的响应头:content-disposition:attachment;filename=xxx
设置响应头:文件MIME类型:content-type
4.将数据写出到response输出流
* 问题:中文文件名
<!--在弹出的下载提示框中:中文展示不出来-->
<a href="/day0504_Response/downloadServlet?filename=九尾.jpg">图片1</a>
* 解决思路:
1.获取客户端使用的浏览器版本信息
2.根据不同的版本信息,设置filename的编码方式不同
* 案例详见:
package cn.itcast.web.download DownloadServlet;
package cn.itcast.web.utils.DownLoadUtils;
download.html;