目录
今日内容
1. HTTP协议:响应消息
2. Response对象
3. ServletContext对象
HTTP协议:
- 请求消息:
- 数据格式
- 请求行
- 请求头
- 空行
- 请求体
- 响应消息
-
数据格式
-
响应行
-
组成:HTTP/1.1 200 OK—> 协议/版本 响应的状态码 状态码的描述
-
响应的状态码:服务器告诉浏览器响应的状态
-
状态码都是3位数字
-
分类
-
1XX:服务器接收到客户端消息,但没有接收完成,过一段时间,会给你回复1XX状态码
-
2XX:这一类型的状态码,代表请求已成功被服务器接收、理解、并接受。200 OK
-
3XX: 重定向,代表:(302),304(访问缓存)
-
4XX:客户端错误(从客户端找问题)
* 代表 * 404 :Not Found(请求的资源未找到) * 405 :Method Not Allowed 5. ==5XX :服务器错误。代表:500(服务器内部出现错误)==
-
响应头
-
格式:头名称:值
-
常见的响应头:
-
Content-Type:服务器告诉浏览器收到了什么格式的数据
text/html;charset=utf-8、jpg、png、、、
-
Content-disposition: 服务器告诉浏览器以什么格式打开响应体数据
-
值:
* in-line:默认值,在当前页面打开 * attachment; filename="xxx":以附件的形式打开响应体。文件下载
- 响应空行
- 响应体:传输数据
-
-
响应数据格式
HTTP/1.1 200 OK
Content-Type: text/html;charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Server: nginx
<!DOCTYPE html>
<html>
<head>
<title>搜狐</title>
<meta name="Keywords" content="搜狐,门户网站,新媒体,网络媒体,新闻,财经,体育,娱乐,时尚,汽车,房产,科技,图片,论坛,微博,博客,视频,电影,电视剧"/>
<link href="//statics.itc.cn/web/v3/static/css/main-93133d8821.css" rel="stylesheet"/>
<script>
// 加载监控代码
</script>
<!--[if lt IE 9]>
<script src="//statics.itc.cn/web/v3/static/js/es5-shim-08e41cfc3e.min.js"></script>
</head>
<body class="sohu-index-v3" data-spm="home">
<header class="sohu-head">
<div class="area sohu-head-box">
<div class="right head-right">
</div>
</div>
</header><div class="sohu-ph" id="sohuTopc" style="display:none;">
<div class="ph-link">
</body>
</html>
Response对象
-
功能: 设置响应消息
-
设置响应行
-
组成:HTTP/1.1 200 OK 协议/版本 响应的状态码 状态码的描述
-
设置响应的状态码:
setStatus(int sc) -
设置响应头:
void setHeader(String name,String value)
编码
- 设置Content-Type
// 1. 第一种方式
```java //作用:设置流的编码,也就是writer()里面数据的编码方式 response.setCharacterEncoding("UTF-8"); //浏览器收到我得文档之后,采用什么编码显示 response.setHeader("Content-Type","text/html;charset=utf-8"); response.getWriter().Write("中文"); ``` //2. 第二种方式: setContentType 直接代替第一种方式中的两句 ```java //两个作用:一是规定流的以什么方式编码,二是规定浏览器以什么方式解码 response.setContentType("text/html;charset=utf-8"); response.getWriter().Write("中文"); ```
-
2. 设置流的打开方式:
* 按照文件下载方式打开
response.setHeader("Content-disposition","attachment; filename=aa.jpg");
> 会跳出一个窗口让你下载文件。
- 设置响应体:
响应体就是返回给客户端浏览器的东西。可以是一个页面,也可以是一个字符串;当然,你的
页面也是使用字符串拼接的。
-
使用步骤
- 获取输出流
方式1. :获取**字符**输出流 PrintWriter getWriter() 方式2.:获取**字节**输出流 ServletOutputStream getOutputStream()
- 使用输出流
方式一:字符输出流--getWriter().Write(); > 字符流处理不了图片等文件。 方式二:字节输出流--getOutputStream().Write();
字节流是万能的,全部都可以给你处理。
```
- 重定向与转发
-
重定向:response.sendRedirect(ctxPath + “/responseDemo2”);
重定向在客户端发生,所以必须带虚拟路径。
-
转发:通过request获取请求转发对象:
RequestDispatcher requestDispatcher = request.getRequestDispatcher(String path);
requestDispatcher.forward(request,response);转发在服务器内部发生,默认带有虚拟路径
-
对比:
转发是一次请求,重定向是新的请求
转发可以使用request传递参数
重定向不可以使用request域传递参数
转发地址栏不发生改变
重定向地址栏转向新地址
- 服务器输出字符数据到浏览器
-
步骤:
- 获取字符输出流
- 输出数据
-
注意:
-
乱码问题:
- PrintWriter pw = response.getWriter();获取的流的默认编码是ISO-8859-1
- 设置该流的默认编码
- 告诉浏览器响应体使用的编码
//简单的形式,设置编码,是在获取流之前设置
response.setContentType(“text/html;charset=utf-8”);
-
-
服务器输出字节数据到浏览器
- 步骤:
- 获取字节输出流
- 输出数据
* 注意:
* 乱码问题:
1. PrintWriter pw = response.getWriter();获取的流的默认编码是ISO-8859-1
2. 设置该流的默认编码
3. 告诉浏览器响应体使用的编码
//简单的形式,设置编码,是在获取流之前设置
response.setContentType(“text/html;charset=utf-8”);
- 服务器输出字节数据到浏览器
* 步骤:
-
获取字节输出流
-
输出数据
- 验证码
-
本质:图片
,但图片是动态生成的
-
目的:防止恶意攻击
- 步骤:
路径问题:
相对路径:
通过相对路径不可以确定唯一资源
两个资源的访问路径的相对,不是你在创建项目的时候文件的相对位置。
也就是说,并不是根据你眼睛看到的文件的位置在哪肉眼判断谁相对谁绝对,而是根据地址栏你访问的路径间具体的关系判断。
如下:
http://localhost:8080/day14_response/pathdemo.html
http://localhost:8080/day14_response/responseDemo5?color=aa
上面两个地址,pathdemo.html是一个页面,responseDemo5?color=aa是一个servlet;
我告诉你,他俩是相对路径。
- 如:./index.html
- 不以/开头,以.开头路径
- 规则:找到当前资源和目标资源之间的相对位置关系
- ./:当前目录,如果默认不写也是当前目录如:./a.jpg == a.jpg
- …/:前进一级目录
绝对路径:
通过绝对路径可以确定唯一资源
- 如:http://localhost/day15/responseDemo2 /day15/responseDemo2
- 以/开头的路径
- 规则:判断定义的路径是给谁用的?判断请求将来从哪儿发出
- 给客户端浏览器使用:需要加虚拟目录(项目的访问路径)
- 建议虚拟目录动态获取:request.getContextPath()
- , 重定向…
- 给服务器使用:不需要加虚拟目录
-
转发路径
-
- 给客户端浏览器使用:需要加虚拟目录(项目的访问路径)
区分/和./
从客户端浏览器出发:
/ 代表根目录host,host指的是—http://localhost:8080/; -------------/是绝对路径,后面不要忘了加虚拟路径
./ 代表的是当前目录。 ---------------./是相对路径
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>路径问题</title>
</head>
<body>
<!--相对路径-->
<div>相对路径</div>
<a href="test.html">test.html</a>
<a href="./index.jsp">index.jsp</a>
<a href="responseDemo5?color=aa">responseDemo5</a>
<!--绝对路径-->
<!--http://localhost:8080/context/-->
<hr>
<div>绝对路径</div>
<div>在客户端(浏览器端)直接写/是只到host的根,到不了虚拟路径的根</div>
<div>错误的</div>
<a href="/index.jsp">index.jsp</a>
<hr>
<div>正确的,可以认为 /day14_response/index.jsp </div>
<div>是http://localhost:8080/day14_response/index.jsp 的简写</div>
<a href="/day14_response/index.jsp">index.jsp</a>
<a href="http://localhost:8080/day14_response/index.jsp">index.jsp</a>
<hr>
<div>服务器端</div>
<a href="/day14_response/responseDemo7">demo7</a>
</body>
</html>
前台标签请求问题
前台标签如:a标签的href属性、img标签的src属性等,
不仅仅可以指向某个资源—href的跳转页面、src的图片;
还可以向后台发送请求。
img
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>验证码</title>
<script type="text/javascript">
window.onload = function (ev) {
//1.获取图片对象
var img = document.getElementById("checkCode");
//2. 添加点击事件
img.onclick = function (ev2) {
// img.src="img/eg_tulip.jpg";
//3.解决缓存的问题
var dt = new Date().getTime();
//4. 动态生成图片, 向后台发送请求
img.src = "/day14_response/responseDemo9?" + dt;
}
}
</script>
</head>
<body>
<img id="checkCode" src="/day14_response/responseDemo9" helo="hello"/>
<a id="change" href="">看不清楚换一张?</a>
</body>
</html>
img.src = “/day14_response/responseDemo9?” + dt;
这是向后台发送请求,请求中带着value,且这个value是时间,
时间是一定不同的,这才能保证每一次请求是新发的,要不然浏览器只是从内存里面读取;
浏览器每次从内存里面读取的话,我们的图片验证码每次点击更换发现都是一样的。
@WebServlet("/responseDemo9")
public class CheckCodeServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// ImageIO.write(image,"jpg",response.getOutputStream());
int width = 100;
int height = 50;
//1.创建一对象,在内存中图片(验证码图片对象)
BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
//2.美化图片
//2.1 填充背景色
Graphics g = image.getGraphics();//画笔对象
g.setColor(Color.PINK);//设置画笔颜色
g.fillRect(0,0,width,height);
//2.2画边框
g.setColor(Color.BLUE);
g.drawRect(0,0,width - 1,height - 1);
String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghigklmnopqrstuvwxyz0123456789";
//生成随机角标
Random ran = new Random();
for (int i = 1; i <= 4; i++) {
int index = ran.nextInt(str.length());
//获取字符
char ch = str.charAt(index);//随机字符
//2.3写验证码
g.drawString(ch+"",width/5*i,height/2);
}
//2.4画干扰线
g.setColor(Color.GREEN);
//随机生成坐标点
for (int i = 0; i < 10; i++) {
int x1 = ran.nextInt(width);
int x2 = ran.nextInt(width);
int y1 = ran.nextInt(height);
int y2 = ran.nextInt(height);
g.drawLine(x1,y1,x2,y2);
}
//3.将图片输出到页面展示。 字节流返回给前台。
// ImageIO是专门处理图片的类。
ImageIO.write(image,"jpg",response.getOutputStream());
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
ImageIO.write(image,“jpg”,response.getOutputStream());
以流的方式返回给前台。
ServletContext对象
-
概念:代表整个web应用程序,可以和程序的容器(服务器)来通信
-
获取:
1. 通过request对象获取
ServletContext servletContext = request.getServletContext();
2. 通过HttpServlet对象获取
ServletContext servletContext1 = this.getServletContext();
1.域对象
1.setAttribute(String name,Object value)
2. getAttribute(String name)
3. removeAttribute(String name)
* 所有用户的所有请求
2. 获取真实文件的路径
-
方法:getRealPath(String path)
获取文件在真实电脑上面的位置。
url是获取当前域名:localhost:8080;
contextPath()是获取虚拟路径。
servletPath()是获取当前请求访问路径。
@WebServlet("/servletContextDemo3")
public class ServletContextDemo3 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//我们来找一下虚拟路径对应的真的电脑上的文件路径
ServletContext servletContext = this.getServletContext();
//后台的“/”的后面默认会有虚拟路径。
System.out.println(servletContext.getRealPath("/")); //D:\EasyTrain\javaWeb\day14_Response\code\day14_response\out\artifacts\day14_response_war_exploded
// 其实/aa.txt == localhost:8080/虚拟路径/aa.txt
System.out.println(servletContext.getRealPath("/aa.txt"));
System.out.println(servletContext.getRealPath("/WEB-INF/bb.txt"));
System.out.println(servletContext.getRealPath("/WEB-INF/classes/cc.txt"));
}
在后台,/后面自动会带上虚拟路径。
getRealPath(“/a.txt”)其实就是localhost:8080/虚拟路径/a.txt在真实电脑上面的位置。
getRealPath(“/WEB-INF/bb.txt”)其实就是localhost:8080/虚拟路径/WEB-INF/bb.txt在真实电脑上面的位置。
但是,注意,WEB-INF/目录只能在后台访问,你在前台访问WEB-INF/是访问不了的。
2.获取MIME类型
* 获取MIME类型:在互联网通信过程中定义的一中文件数据类型
```java
@WebServlet("/servletContextDemo4")
public class ServletContextDemo4 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//我们来找一下虚拟路径对应的真的电脑上的文件路径
ServletContext servletContext = this.getServletContext();
//获取MIME类型
System.out.println(servletContext.getMimeType("aa.jpg"));
System.out.println(servletContext.getMimeType("aa.mp4"));
}
```
3.文件下载的功能
WEB-INF在前台是不能访问的。只能在后台访问。
-
页面显示超链接
-
点击超链接提示下载
-
保存完成文件的下载
* 分析:
\1. 超链接指向一个程序
\2. 点击超链接,使用字节流的方式返回数据
\3. 使用响应头设置资源的打开类型:
* content-disposition:attachment;filename=xxx
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>下载</title>
</head>
<body>
<!--超链接,路径跳转-->
<a href="img/img1.jpg">图片</a>
<div>HTTP Status 404 – Not Found</div>
<!--WEB-INF 前台是不能访问他下面的文件的-->
<a href="/day14_response/WEB-INF/bb.txt">bb</a>
<hr>
<!--前台href像后台发请求, 带着参数过去-->
<a href="/day14_response/downloadDemo1?filename=中文abc国家.jpg">下载</a>
</body>
</html>
@WebServlet("/downloadDemo1")
public class DownLoadServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1. 拿到文件名
String filename = request.getParameter("filename");
// 找到真实路径
String realPath = this.getServletContext().getRealPath("/img/" + filename);
ServletOutputStream outputStream = response.getOutputStream(); //获取字节流
byte[] bytes = new byte[1024*8]; //缓冲区
// for(byte i=0;i<100;i++){
// bytes[i] =i;
// }
//2. 打开文件
FileInputStream fis = new FileInputStream(realPath);
//3. 读取字节流
//4. 将字节流写入管道(网络),以字节流的方式返回数据
// content-disposition:attachment;filename=?????.jpg
// content-disposition:attachment;filename=中文服务器.jpg
// response.setHeader("content-disposition","attachment;filename=中文服务器.jpg");
// response.setHeader("content-disposition","attachment;filename=%e4%b8%ad%e5%9b%bd.jpg");
//获取浏览器类型
//把浏览器类型当做参数传给getFileName方法
//不同的浏览器对中文文件名称的处理还不一样,需要做另外的处理
response.setHeader("content-disposition","attachment;filename=" + getFileName("chrome",filename));
int len;
while((len=fis.read(bytes))!=-1){
//返回给前台
outputStream.write(bytes,0,len);
}
fis.close();
}
public static String getFileName(String agent, String filename) throws UnsupportedEncodingException {
if (agent.contains("MSIE")) {
// IE浏览器
filename = URLEncoder.encode(filename, "utf-8");
filename = filename.replace("+", " ");
} else if (agent.contains("Firefox")) {
// 火狐浏览器
BASE64Encoder base64Encoder = new BASE64Encoder();
filename = "=?utf-8?B?" + base64Encoder.encode(filename.getBytes("utf-8")) + "?=";
} else {
// 其它浏览器
filename = URLEncoder.encode(filename, "utf-8");
}
return filename;
}
}
edEncodingException {
if (agent.contains(“MSIE”)) {
// IE浏览器
filename = URLEncoder.encode(filename, “utf-8”);
filename = filename.replace("+", " ");
} else if (agent.contains(“Firefox”)) {
// 火狐浏览器
BASE64Encoder base64Encoder = new BASE64Encoder();
filename = “=?utf-8?B?” + base64Encoder.encode(filename.getBytes(“utf-8”)) + “?=”;
} else {
// 其它浏览器
filename = URLEncoder.encode(filename, “utf-8”);
}
return filename;
}
}