1 响应对象
1.1 响应对象概述
1.1.1 关于响应
响应,它表示了服务器端收到请求,同时也已经处理完成,把处理的结果告知用户。简单来说,指的就是服务器把请求的处理结果告知客户端。在B/S架构中,响应就是把结果带回浏览器。
响应对象,顾名思义就是用于在JavaWeb工程中实现上述功能的对象。
1.1.2 常用响应对象
响应对象也是是Servlet规范中定义的,它包括了协议无关的和协议相关的。
协议无关的对象标准是:ServletResponse接口
协议相关的对象标准是:HttpServletResponse接口
类结构图如下:
我们课程中涉及的响应对象都是和HTTP协议相关的。即使用的是HttpServletResponse接口的实现类。
这里有些同学可能会产生疑问,我们在使用Servlet时,需要定义一个类,然后实现Servlet接口(或者继承它的实现类)。现在我们想要实现响应功能,要不要定义一个类,然后实现HttpServletResponse接口呢?
此问题的答案是否定的,我们无需这么做。我们只需要在自己写的Servlet中直接使用即可,因为这个对象的实现类是由Tomcat提供的,无须我们自定义。同时它还会帮我们把对象创建出来并传入doGet和doPost方法中。
1.2 常用方法介绍
在HttpServletResponse接口中提供了很多方法,接下来我们通过API文档,来了解一下这些方法。
常用状态码:
状态码 | 说明 |
200 | 执行成功 |
302 | 它和307一样,都是用于重定向的状态码。只是307目前已不再使用 |
304 | 请求资源未改变,使用缓存。 |
400 | 请求错误。最常见的就是请求参数有问题 |
404 | 请求资源未找到 |
405 | 请求方式不被支持 |
500 | 服务器运行内部错误 |
状态码首位含义:
状态码 | 说明 |
1xx | 消息 |
2xx | 成功 |
3xx | 重定向 |
4xx | 客户端错误 |
5xx | 服务器错误 |
1.3 响应对象的使用示例
1.3.1 响应-字节流输出中文问题
返回值 方法名 说明
ServletOutputStream getOutputStream() 获取响应字节输出流对象
void setContentType("text/html";charset="utf-8") 设置响应内容类型,解决中文乱码问题
package com.itheima.Servlet;
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.nio.charset.StandardCharsets;
/*
* 字节流响应消息
* 问题:
* String str = "字节流中文乱码问题";
* 使用字节流输出,会不会产生中文乱码?
* 答案:
* 会产生乱码
* 原因:
* String str = "字节流中文乱码问题"; 在保存时用的是IDEA创建文件使用的字符集UTF-8。
* 到浏览器上显示,chrome浏览器和ie浏览器默认的字符集是GB2312(其实就是GBK),存和取用的不是同一个码表,就会产生乱码。
*
* 引申:
* 如果产生了乱码,就是存和取用的不是同一个码表
* 解决办法:
* 把存和取的码表统一。
*/
* */
@WebServlet("/servletDemo01")
public class ServletDemo01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=UTF-8");
//获取字节输出流对象
ServletOutputStream os = resp.getOutputStream();
//定义一个消息
String str="你好";
//通过字节流对象输出
os.write(str.getBytes("utf-8"));
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
字符流响应消息
返回值 方法名 说明
PrintWriter getWriter() 获取响应字符输出流对象
void setContentType("text/html;charset=utf-8") 设置响应内容类型,解决中文乱码问题
1.3.2 响应-字符流输出中文问题
package com.itheima.Servlet;
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.PrintWriter;
/*
* 字符流响应消息
*
*/
@WebServlet("/servletDemo02")
public class ServletDemo02 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=UTF-8");
//获取到字符输出流对象
PrintWriter pw = resp.getWriter();
//准备一个消息
String str="你好";
//通过字符流输出
pw.write(str);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
响应图片
1.创建字节输入流对象,关联读取的图片路径
2.通过响应对象获取字节输出流对象
3.循环读取和写出图片
package com.itheima.Servlet;
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.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
/*
* 响应图片
*
*/
@WebServlet("/servletDemo03")
public class ServletDemo03 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//通过文件的相对路径获取绝对路径
String realPath = getServletContext().getRealPath("/img/Request.png");
System.out.println(realPath);
//创建字节输入流对象,关联图片路径
BufferedInputStream bis=new BufferedInputStream(new FileInputStream(realPath));
//通过响应对象获取字节输出流对象
ServletOutputStream os = resp.getOutputStream();
//循环读写操作
byte[] arr=new byte[1024];
int len;
while((len=bis.read(arr))!=-1){
os.write(arr,0,len);
}
//释放资源
bis.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
设置缓存:
缓存:对于不经常变化的数据,我们可以设置合理缓存时间,以避免浏览器频繁请求服务器 ,以此来提高效率!
返回值 方法名 说明
void setDateHeader(String name,long time) 设置 消息头,添加缓存
package com.itheima.Servlet;
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.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
/*
* 设置缓存
*
*/
@WebServlet("/servletDemo04")
public class ServletDemo04 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String news="这是一条很火爆的新闻";
//设置缓存 1小时的缓存时间
resp.setDateHeader("Expires",System.currentTimeMillis()+1*60*60*1000);
//设置编码的格式
resp.setContentType("text/html;charset=UTF-8");
//写出数据
resp.getWriter().write(news);
System.out.println("aaa");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
定时刷新:过了指定时间后,页面自动进行跳转
返回值 方法名 说明
void setHeader(String name,String value) 设置消息头定时刷新
package com.itheima.Servlet;
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("/servletDemo05")
public class ServletDemo05 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String str="您的用户名或密码有误,三秒后自动跳转到登陆页面";
resp.setContentType("text/html;charset=utf-8");
//写出数据
resp.getWriter().write(str);
//定时刷新
resp.setHeader("Refresh","3,URL=/response/login.html");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
1.3.6 请求重定向:注意地址栏发生改变。
客户端的一次请求到达后,发现需要借助其他Servlet来实现功能
特点:浏览器地址栏会发生改变,两次请求,请求域对象中不能共享数据,可以重定向到其他服务器。
重定向的实现原理
设置响应状态码为302 resp.setStatus(302);
设置相应的资源路径(响应到哪里去,通过响应消息头location来指定)
resp.setHeader("location","response/responseDemo07")
响应对象重定向方法
返回值 方法名 说明
void sendRedirect(String name) 设置重定向
ResponseDemo6
package com.itheima.Servlet;
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("/servletDemo06")
public class ServletDemo06 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("servletDemo06执行了");
//设置请求共享数据
req.setAttribute("username","张三");
//设置重定向
resp.sendRedirect(req.getContextPath()+"/servletDemo07");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
ResponseDemo7
public class ResponseDemo7 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.getWriter().write("welcome to ResponseDemo7");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
1.3.3 响应-生成验证码
package com.itheima.Servlet;
import javax.imageio.ImageIO;
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 javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
/*
* 图片显示验证码
*
*/
@WebServlet("/servletDemo08")
public class ServletDemo08 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
int width=200;
int height=35;
/*
* 1.创建图像内存对象
* 2.拿到画笔
* 3.设置颜色,画矩形边框
* 4.设置颜色,填充矩形
* 5.设置颜色,画干扰线
* 6.设置颜色,画验证码
* 7.把内存图像输出到浏览器上
* */
//创建内存图像
BufferedImage image=new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);//参数:宽度,高度(指的都是像素),使用的格式(RGB)
Graphics g=image.getGraphics();//画笔就一根
//设置颜色
g.setColor(Color.BLUE);
//画边框
g.drawRect(0,0,width,height);
//设置颜色
g.setColor(Color.GRAY);
//填充矩形
g.fillRect(1,1,width-2,width-2);
//设置颜色
g.setColor(Color.WHITE);
//那随机数对象
Random r=new Random();
//话干扰线10条
for (int i = 0; i < 10; i++) {
g.drawLine(r.nextInt(width),r.nextInt(height),r.nextInt(width),r.nextInt(height));
}
//设置颜色
g.setColor(Color.red);
//改变字体大小
Font font=new Font("宋体",Font.BOLD,30);
g.setFont(font);//设置字体
//画验证码 4个
int x=35;
for (int i = 0; i < 4; i++) {
g.drawString(String.valueOf(10),x,25);
x+=35;
}
//输出到浏览器上
//参数:1.内存对象。2.输出的图片格式。3.使用额输出流
ImageIO.write(image,"jpg",resp.getOutputStream());
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
1.3.7 响应和消息头组合应用-文件下载
1.创建字节输入流,关联 读取的文件
2.设置响应消息头支持的类型
3.设置响应消息头以下载方式打开资源
4.通过响应对象获取字节输出流对象
5.循环读写
6.释放资源
package com.itheima.Servlet;
import javax.imageio.ImageIO;
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.awt.*;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Random;
/*
* 下载文件
*
*/
@WebServlet("/servletDemo09")
public class ServletDemo09 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.创建字节输入流,关联 读取的文件
String realPath = getServletContext().getRealPath("/img/Request.png");
BufferedInputStream bis=new BufferedInputStream(new FileInputStream(realPath));
/*
* Content-Type 消息头名称 支持的类型
* application/octet-stream 消息头参数 应用的类型为字节流
* */
//2.设置响应消息头支持的类型
resp.setHeader("Content-Type","application/octet-stream");
//3.设置响应消息头以下载方式打开资源
/*
* Content-Disposition 消息头名称 处理的形式
* attachment;filename=Request.png 消息头参数 附件形式进行处理 指定下载文件的名称
* */
resp.setHeader("Content-Disposition","attachment;filename=Request.png");
//4.通过响应对象获取字节输出流对象
ServletOutputStream os = resp.getOutputStream();
//5.循环读写
byte []arr=new byte[1024];
int len;
while((len= bis.read(arr))!=-1){
os.write(arr,0,len);
}
//6.释放资源
bis.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}