01_响应对象的概述&向客户端发送数据
WEB服务器会针对每一个客户端发出的HTTP请求,分别的创建一个请求对象和一个响应对象
如果需要获取客户端提交的数据,需要使用请求对象
如果需要向客户端发送一些数据,需要使用响应对象
响应: 响应行(响应的协议 状态码 ) 响应头(键值对) 响应体
1XX:浏览器发送的请求信息不完善,需要浏览器进一步补充资料
2XX:响应正常完成
3XX:本次请求已经完成,但是需要浏览器进行进一步操作 304 302
4XX:请求资源错误
5XX:服务器错误
注意:
响应中的两个流相互排斥,在一个Servlet中只能使用其中一个
图片,音视频用字节流,处理文本用字符流
字节输出流不能直接写一个字符串,只能写一个字节或者字节数组(string.getByte())
02_字节流向客户端发送中文的乱码处理
编码: 计算机 二进制 (十进制数据表示:A--65 a--97)再转换为二进制进行存储
ASCII 美国标准信息码(128个字符)
ISO-8859-1 -16 没有-13 一共15个编码 不能存中文
GB2312:使用2个字节表示一个字符 容纳6700+汉字
GBK:使用2个字节表示一个字符 可以容纳18000+汉字 国家的强制标准
Unicode:万国码 使用2个字节表示一个字符
UTF-8:Unicode Transfer Format-8:Unicode转换码 使用1-6个字节表示一个字符
ANSI:本地平台默认的,跟当前的操作系统有关 中文版的window--GBK 英文版window --UTF-8
原因:
乱码的出现是因为前后编码不一致,发送数据的编码,接收数据的编码
PrintWriter pw = response.getWriter();
pw.println("传智播客");
服务器发送数据:ISO-8859-1
浏览器接收数据:GBK(中文版的window--GBK)
使用字节流输出的方式解决
解决方法一
//将服务器发送数据的格式改成GBK
OutputStream os = response.getOutputStream();
os.write("黑马程序员".getBytes());//创建字符串,默认的是GBK,getBytes()转成字节数组,也是默认的GBK
解决方法二
//设置响应头,告诉浏览器你应该使用什么编码解析
OutputStream os = response.getOutputStream();
os.write("黑马程序员".getBytes("UTF-8"));//发送采用UTF-8
response.setHeader("Content-type", "text/html;charset=UTF-8");//告诉浏览器你使用UTF-8解析
//简化写法 response.setContentType("text/html;charset=UTF-8");
03_字符流向客户端发送中文的乱码处理
PrintWriter pw = response.getWriter();
pw.println("传智播客");
原因:
服务器发送数据:ISO-8859-1
浏览器接收数据:GBK
仍然使用字符流输出
解决方法一
response.setCharacterEncoding("GBK");//设置响应的编码格式为GBK,也就是设置服务器发送数据格式
如果服务器端发送的是UTF-8呢
response.setCharacterEncoding("UTF-8");//设置响应的编码格式为UTF-8,也就是设置服务器发送数据格式
response.setContentType("text/html;charset=UTF-8");//告诉浏览器采用什么编码进行解析
解决方法二(推荐)
response.setContentType("text/html;charset=UTF-8");//设置了响应的编码,也设置了创建字符输出流所使用的编码
终极方案
对于响应对象的乱码问题,只需要设置一行代码response.setContentType("text/html;charset=UTF-8");
04_响应头Refresh
定时自动刷新
response.setHeader("Refresh", "3");
定时自动跳转(定时重定向)
response.setHeader("Refresh", "3;URL=http://www.itcast.cn");//跳转外部资源
response.setHeader("Refresh", "3;URL=/myResponse/ResponseDemo");//跳转内部资源
注意:跳转使用的客户端路径 需要/项目名
转发和跳转的区别
转发:共享请求和响应对象 跳转:不共享
转发:只能是内部地址 跳转:内部地址和外部地址都可以
转发:地址栏不会发生变化 跳转:地址栏会发生变化
05_请求重定向(立即重定向)
概念:一个web资源接收到客户端的请求之后,通知客户端去访问另外一个web资源
用法:
response.sendRedirect("http://www.baidu.com");
原理:
设置location响应头,同时还需要设置一个响应码 302/307
//response.setHeader("Location", "http://www.itcast.cn");
//response.setStatus(307);
重定向和转发的区别
请求响应的次数
转发:一次请求,一次响应
重定向:两次请求,两次响应
浏览器的地址
转发:地址栏保存初值不变
重定向:改变为重定向的页面地址
作用范围
转发:只能是同一个项目
重定向:可以定向到其他项目或者服务器
URL以/开头的含义不同
转发:代表当前web应用的根路径
重定向:代表web服务器的根路径
变量的作用域
转发:request中存放的变量不会失效
重定向:request中存放的变量会失效,进入一个新的request作用域
各自优点
转发:相对的高效,隐藏实际的链接地址
重定向:能跳转到其他的服务器上的资源
06_文件下载案例
步骤
//设置响应头
response.setHeader("Content-disposition", "attachment;filename=pic01.jpg");
//获取字节输出流对象
OutputStream os = response.getOutputStream();
//创建字节输入流对象
String path = getServletContext().getRealPath("/WEB-INF/pic01.jpg");
FileInputStream fis = new FileInputStream(path);
//循环读取并向客户端发送数据
int len = 0;
byte[] bys = new byte[1024];
while((len = fis.read(bys)) != -1) {
//向客户端发送数据
os.write(bys,0,len);
}
//释放资源
fis.close();
07_文件下载的细节
更改如下:
String s = URLEncoder.encode("传智专修学院.jpg", "UTF-8");
response.setHeader("Content-disposition", "attachment;filename=" + s);
注意:
响应头里面不能有中文的,中文被认为是不安全的字符
WEB-INF里面的资源不能直接访问,主要用来存放一些重要的资源
08_请求对象的概述&获取请求行
HttpServletRequest
请求对象封装了HTTP协议的请求行,请求头,请求体,我们可以通过请求对象的方法来获取这些信息
获取请求行
StringBuffer getRequestURL() //完整的URL
String getRequestURI() //请求行中的资源路径
String getMethod() //请求方式 *****************
String getContextPath() //当前项目的路径 *****************
String getQueryString() //请求行中资源路径后面的参数
注意:
getRequestURL()返回的是一个可变的字符串,不能直接用String接收
getQueryString()获取的是资源路径后面的参数,请求体里面的数据无法获取
URL和URI区别
URL 统一资源定位符
URI 统一资源标识符
URI 强调给资源标记命名,URL强调的是给资源定位
URL里面包含的信息比URI多
总结
URI标记了一个网络资源,仅此而已,URL标记了一个www互联网资源,并且给出了访问地址
09_获取请求头
String getHeader(String name) //通过name来获取请求头value
Enumeration getHeaderNames() //获取所有的请求头name
//迭代器遍历
Enumeration<String> e = request.getHeaderNames();
while(e.hasMoreElements()) {
String name = e.nextElement();
System.out.println(name);
}
10_获取表单提交的数据
String getParameter(String name) :根据表单项的name来获取表单项的value
注意:
有表单项提交过来,但是没有值,打印的是空字符串
表单项根本就没有提交过来,打印的null,就不能调用字符串的方法,否则会报空指针异常
11_获取表单提交的数据2
String[] getParameterValues(String name) 根据表单项的name获取表单项value的数组
应用场景:name是重复的,密码和确认密码,复选框
12_获取表单提交的数据3
Map getParameterMap(): 获取表单提交来的所有数据,并封装成一个map返回,一些框架(工具类)会使用这个方法
Enumeration getParameterNames() 获取提交过来表单项所有的name
返回值使用泛型时应该是Map<String,String[]>形式,
因为有时像checkbox这样的组件会有一个name对应多个value的时候,
所以该Map中键值对是<String-->String[]>的实现。
注意:
注册按钮提交过来是没有意义的,所以注册按钮没有必要写name属性
*****表单提交项必须有name属性,否则服务器获取不了*****
14_获取表单提交的数据乱码的处理
原因:
编码前后不一致
表单提交数据用的是UTF-8(将原始的数据用UTF-8进行编码然后发给服务器)
请求对象接收数据转化成字符串 用的是默认的ISO-8859-1
对于post请求
request.setCharacterEncoding("UTF-8");//只能处理请求体,设置请求对象创建字符串所使用的编码是UTF-8
对于get请求
浏览器
按照表单页面的编码(UTF-8)进行转码,转成字节数组,拼接在请求资源后面
接下来把字节数组做一个转义(URl编码)在发送过去
服务器
服务器首先拿到这个数据之后,做一个url解码(正确)
然后把解码之后的数据按照ISO-8859-1拼成字符串(错误)
做法:
//把字符串打回原形
byte[] bys = request.getParameter("username").getBytes("ISO-8859-1");
//把字节数组按照正确的编码转换字符串
String username = new String(bys,"UTF-8");
15_转发和包含
用ServletContext实现转发和包含,路径必须以正斜杠开头
RequestDispatcher rd = getServletContext().getRequestDispatcher("/register.html");
rd.forward(request, response);
rd.include(request, response);
用request对象实现转发和包含,路径可以不用正斜杠开头
RequestDispatcher rd = request.getRequestDispatcher("register.html");
rd.forward(request, response);
rd.include(request, response);
16_使用请求对象实现数据共享
域对象3个基本方法
//设置数据
request.setAttribute("username", "zhangsan");
//获取数据
Object obj = request.getAttribute("username");
//删除数据
request.removeAttribute("username");
//转发可以共享请求响应对象
RequestDispatcher rd = request.getRequestDispatcher("/RequestDemo9");
rd.forward(request, response);
ServletContext 上下文对象 范围是当前的web应用
时间范围 tomcat一加载就会创建 tomcat关闭 销毁
空间范围 整个web应用
request 请求对象 范围是当前的请求 需要是同一个请求,才能实现数据的共享
时间范围 一个请求开始到这个请求结束
空间范围 当前这个请求里面
访问网站的统计量(ServletContext)
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext context = getServletContext();
//首先看看他有没有count属性
//如果没有的话,就给他设置一个count属性
//如果有是话,count属性的值+1
Integer count = (Integer) context.getAttribute("count");
if (count == null) {
context.setAttribute("count", 1);
}else {
context.setAttribute("count", count + 1);
}
response.getWriter().println("<h1>"+count+"</h1>");
}
WEB服务器会针对每一个客户端发出的HTTP请求,分别的创建一个请求对象和一个响应对象
如果需要获取客户端提交的数据,需要使用请求对象
如果需要向客户端发送一些数据,需要使用响应对象
响应: 响应行(响应的协议 状态码 ) 响应头(键值对) 响应体
1XX:浏览器发送的请求信息不完善,需要浏览器进一步补充资料
2XX:响应正常完成
3XX:本次请求已经完成,但是需要浏览器进行进一步操作 304 302
4XX:请求资源错误
5XX:服务器错误
注意:
响应中的两个流相互排斥,在一个Servlet中只能使用其中一个
图片,音视频用字节流,处理文本用字符流
字节输出流不能直接写一个字符串,只能写一个字节或者字节数组(string.getByte())
02_字节流向客户端发送中文的乱码处理
编码: 计算机 二进制 (十进制数据表示:A--65 a--97)再转换为二进制进行存储
ASCII 美国标准信息码(128个字符)
ISO-8859-1 -16 没有-13 一共15个编码 不能存中文
GB2312:使用2个字节表示一个字符 容纳6700+汉字
GBK:使用2个字节表示一个字符 可以容纳18000+汉字 国家的强制标准
Unicode:万国码 使用2个字节表示一个字符
UTF-8:Unicode Transfer Format-8:Unicode转换码 使用1-6个字节表示一个字符
ANSI:本地平台默认的,跟当前的操作系统有关 中文版的window--GBK 英文版window --UTF-8
原因:
乱码的出现是因为前后编码不一致,发送数据的编码,接收数据的编码
PrintWriter pw = response.getWriter();
pw.println("传智播客");
服务器发送数据:ISO-8859-1
浏览器接收数据:GBK(中文版的window--GBK)
使用字节流输出的方式解决
解决方法一
//将服务器发送数据的格式改成GBK
OutputStream os = response.getOutputStream();
os.write("黑马程序员".getBytes());//创建字符串,默认的是GBK,getBytes()转成字节数组,也是默认的GBK
解决方法二
//设置响应头,告诉浏览器你应该使用什么编码解析
OutputStream os = response.getOutputStream();
os.write("黑马程序员".getBytes("UTF-8"));//发送采用UTF-8
response.setHeader("Content-type", "text/html;charset=UTF-8");//告诉浏览器你使用UTF-8解析
//简化写法 response.setContentType("text/html;charset=UTF-8");
03_字符流向客户端发送中文的乱码处理
PrintWriter pw = response.getWriter();
pw.println("传智播客");
原因:
服务器发送数据:ISO-8859-1
浏览器接收数据:GBK
仍然使用字符流输出
解决方法一
response.setCharacterEncoding("GBK");//设置响应的编码格式为GBK,也就是设置服务器发送数据格式
如果服务器端发送的是UTF-8呢
response.setCharacterEncoding("UTF-8");//设置响应的编码格式为UTF-8,也就是设置服务器发送数据格式
response.setContentType("text/html;charset=UTF-8");//告诉浏览器采用什么编码进行解析
解决方法二(推荐)
response.setContentType("text/html;charset=UTF-8");//设置了响应的编码,也设置了创建字符输出流所使用的编码
终极方案
对于响应对象的乱码问题,只需要设置一行代码response.setContentType("text/html;charset=UTF-8");
04_响应头Refresh
定时自动刷新
response.setHeader("Refresh", "3");
定时自动跳转(定时重定向)
response.setHeader("Refresh", "3;URL=http://www.itcast.cn");//跳转外部资源
response.setHeader("Refresh", "3;URL=/myResponse/ResponseDemo");//跳转内部资源
注意:跳转使用的客户端路径 需要/项目名
转发和跳转的区别
转发:共享请求和响应对象 跳转:不共享
转发:只能是内部地址 跳转:内部地址和外部地址都可以
转发:地址栏不会发生变化 跳转:地址栏会发生变化
05_请求重定向(立即重定向)
概念:一个web资源接收到客户端的请求之后,通知客户端去访问另外一个web资源
用法:
response.sendRedirect("http://www.baidu.com");
原理:
设置location响应头,同时还需要设置一个响应码 302/307
//response.setHeader("Location", "http://www.itcast.cn");
//response.setStatus(307);
重定向和转发的区别
请求响应的次数
转发:一次请求,一次响应
重定向:两次请求,两次响应
浏览器的地址
转发:地址栏保存初值不变
重定向:改变为重定向的页面地址
作用范围
转发:只能是同一个项目
重定向:可以定向到其他项目或者服务器
URL以/开头的含义不同
转发:代表当前web应用的根路径
重定向:代表web服务器的根路径
变量的作用域
转发:request中存放的变量不会失效
重定向:request中存放的变量会失效,进入一个新的request作用域
各自优点
转发:相对的高效,隐藏实际的链接地址
重定向:能跳转到其他的服务器上的资源
06_文件下载案例
步骤
//设置响应头
response.setHeader("Content-disposition", "attachment;filename=pic01.jpg");
//获取字节输出流对象
OutputStream os = response.getOutputStream();
//创建字节输入流对象
String path = getServletContext().getRealPath("/WEB-INF/pic01.jpg");
FileInputStream fis = new FileInputStream(path);
//循环读取并向客户端发送数据
int len = 0;
byte[] bys = new byte[1024];
while((len = fis.read(bys)) != -1) {
//向客户端发送数据
os.write(bys,0,len);
}
//释放资源
fis.close();
07_文件下载的细节
更改如下:
String s = URLEncoder.encode("传智专修学院.jpg", "UTF-8");
response.setHeader("Content-disposition", "attachment;filename=" + s);
注意:
响应头里面不能有中文的,中文被认为是不安全的字符
WEB-INF里面的资源不能直接访问,主要用来存放一些重要的资源
08_请求对象的概述&获取请求行
HttpServletRequest
请求对象封装了HTTP协议的请求行,请求头,请求体,我们可以通过请求对象的方法来获取这些信息
获取请求行
StringBuffer getRequestURL() //完整的URL
String getRequestURI() //请求行中的资源路径
String getMethod() //请求方式 *****************
String getContextPath() //当前项目的路径 *****************
String getQueryString() //请求行中资源路径后面的参数
注意:
getRequestURL()返回的是一个可变的字符串,不能直接用String接收
getQueryString()获取的是资源路径后面的参数,请求体里面的数据无法获取
URL和URI区别
URL 统一资源定位符
URI 统一资源标识符
URI 强调给资源标记命名,URL强调的是给资源定位
URL里面包含的信息比URI多
总结
URI标记了一个网络资源,仅此而已,URL标记了一个www互联网资源,并且给出了访问地址
09_获取请求头
String getHeader(String name) //通过name来获取请求头value
Enumeration getHeaderNames() //获取所有的请求头name
//迭代器遍历
Enumeration<String> e = request.getHeaderNames();
while(e.hasMoreElements()) {
String name = e.nextElement();
System.out.println(name);
}
10_获取表单提交的数据
String getParameter(String name) :根据表单项的name来获取表单项的value
注意:
有表单项提交过来,但是没有值,打印的是空字符串
表单项根本就没有提交过来,打印的null,就不能调用字符串的方法,否则会报空指针异常
11_获取表单提交的数据2
String[] getParameterValues(String name) 根据表单项的name获取表单项value的数组
应用场景:name是重复的,密码和确认密码,复选框
12_获取表单提交的数据3
Map getParameterMap(): 获取表单提交来的所有数据,并封装成一个map返回,一些框架(工具类)会使用这个方法
Enumeration getParameterNames() 获取提交过来表单项所有的name
返回值使用泛型时应该是Map<String,String[]>形式,
因为有时像checkbox这样的组件会有一个name对应多个value的时候,
所以该Map中键值对是<String-->String[]>的实现。
注意:
注册按钮提交过来是没有意义的,所以注册按钮没有必要写name属性
*****表单提交项必须有name属性,否则服务器获取不了*****
14_获取表单提交的数据乱码的处理
原因:
编码前后不一致
表单提交数据用的是UTF-8(将原始的数据用UTF-8进行编码然后发给服务器)
请求对象接收数据转化成字符串 用的是默认的ISO-8859-1
对于post请求
request.setCharacterEncoding("UTF-8");//只能处理请求体,设置请求对象创建字符串所使用的编码是UTF-8
对于get请求
浏览器
按照表单页面的编码(UTF-8)进行转码,转成字节数组,拼接在请求资源后面
接下来把字节数组做一个转义(URl编码)在发送过去
服务器
服务器首先拿到这个数据之后,做一个url解码(正确)
然后把解码之后的数据按照ISO-8859-1拼成字符串(错误)
做法:
//把字符串打回原形
byte[] bys = request.getParameter("username").getBytes("ISO-8859-1");
//把字节数组按照正确的编码转换字符串
String username = new String(bys,"UTF-8");
15_转发和包含
用ServletContext实现转发和包含,路径必须以正斜杠开头
RequestDispatcher rd = getServletContext().getRequestDispatcher("/register.html");
rd.forward(request, response);
rd.include(request, response);
用request对象实现转发和包含,路径可以不用正斜杠开头
RequestDispatcher rd = request.getRequestDispatcher("register.html");
rd.forward(request, response);
rd.include(request, response);
16_使用请求对象实现数据共享
域对象3个基本方法
//设置数据
request.setAttribute("username", "zhangsan");
//获取数据
Object obj = request.getAttribute("username");
//删除数据
request.removeAttribute("username");
//转发可以共享请求响应对象
RequestDispatcher rd = request.getRequestDispatcher("/RequestDemo9");
rd.forward(request, response);
ServletContext 上下文对象 范围是当前的web应用
时间范围 tomcat一加载就会创建 tomcat关闭 销毁
空间范围 整个web应用
request 请求对象 范围是当前的请求 需要是同一个请求,才能实现数据的共享
时间范围 一个请求开始到这个请求结束
空间范围 当前这个请求里面
访问网站的统计量(ServletContext)
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext context = getServletContext();
//首先看看他有没有count属性
//如果没有的话,就给他设置一个count属性
//如果有是话,count属性的值+1
Integer count = (Integer) context.getAttribute("count");
if (count == null) {
context.setAttribute("count", 1);
}else {
context.setAttribute("count", count + 1);
}
response.getWriter().println("<h1>"+count+"</h1>");
}