response、request对象

Tomcat收到客户端的http请求,会针对每一次请求,分别创建一个代表请求的request对象、和代表响应的response对象

既然request对象代表http请求,那么我们获取浏览器提交过来的数据,找request对象即可。response对象代表http响应,那么我们向浏览器输出数据,找response对象即可。

什么是HttpServletResponse对象?

http响应由状态行、实体内容、消息头、一个空行组成。HttpServletResponse对象就封装了http响应的信息。

HttpServletResponse的应用

调用getOutputStream()方法向浏览器输出数据

  • 调用getOutputStream()方法向浏览器输出数据,getOutputStream()方法可以使用print()也可以使用write(),它们有什么区别呢?我们试验一下。代码如下

//获取到OutputStream流
ServletOutputStream servletOutputStream = response.getOutputStream(); //向浏览器输出数据
servletOutputStream.print("aaaa");
  • 成功输出,好像没什么毛病。

  • 我们试着输出中文试试

//获取到OutputStream流
ServletOutputStream servletOutputStream = response.getOutputStream(); //向浏览器输出数据
servletOutputStream.print("中国!");
  • 出异常了!!!

  • 为什么会出现异常呢?在io中我们学过,outputStream是输出二进制数据的print()方法接收了一个字符串print()方法要把“中国”改成二进制数据,Tomcat使用IOS 8859-1编码对其进行转换,“中国”根本对ISO 8859-1编码不支持。所以出现了异常
  • 我们再看看write()方法,先向浏览器输出英文数据

response.getOutputStream().write("aaa".getBytes());
  • 没有问题

  • 再试试输出中文数据

response.getOutputStream().write("你好呀我是中国".getBytes());
  • 貌似也没有问题。

  • 为什么使用write()方法能够正常向浏览器输出中文呢?"你好呀我是中国".getBytes()这句代码在转成byte[]数组的时候默认查的是gb2312编码,而“你好呀我是中国”支持gb2312编码,所以可以正常显示出来。
  • 但是,程序要实现通用性,应该使用的是UTF-8编码,我们在字符串转换成字节数组时指定UTF-8编码,看看会怎么样。

response.getOutputStream().write("你好呀我是中国".getBytes("UTF-8"));
  • 好的,成功把它搞成乱码了!!!

  • 为什么它变成了乱码呢?原因是这样的:我在向服务器输出的中文是UTF-8编码的,而浏览器采用的是GBK,GBK想显示UTF-8的中文数据,不乱码才怪呢



- 既然如此,我将浏览器的编码改成UTF-8试试。

  • 乱码问题又解决了。可是,每次编写UTF-8程序时都要去网页上改编码格式吗?这样明显不可能的
  • 既然HTTP响应有对浏览器说明回送数据是什么类型的消息头,那么HttpServletResponse对象就应该有相对应的方法告诉浏览器回送的数据编码格式是什么
  • 于是乎就去查找Servlet API,找到了设置消息头的方法

//设置头信息,告诉浏览器我回送的数据编码是utf-8的
response.setHeader("Content-Type", "text/html;charset=UTF-8"); response.getOutputStream().write("你好呀我是中国".getBytes("UTF-8"));
  • 浏览器在显示数据时,自动把页面的编码格式置换成UTF-8,乱码问题也解决了

  • 另外,除了使用HttpServletResponse对象设置消息头的方法,我可以使用html的标签模拟一个http消息头

  • 下面是代码:


//获取到servletOutputStream对象
ServletOutputStream servletOutputStream = response.getOutputStream(); //使用meta标签模拟http消息头,告诉浏览器回送数据的编码和格式
servletOutputStream.write("<meta http-equiv='content-type' content='text/html;charset=UTF-8'>".getBytes()); servletOutputStream.write("我是中国".getBytes("UTF-8"));
  • 乱码问题也可以解决

调用getWriter()方法向浏览器输出数据

  • 对于getWriter()方法而言,是Writer的子类,那么只能向浏览器输出字符数据,不能输出二进制数据
  • 使用getWriter()方法输出中文数据,代码如下:

//获取到printWriter对象
PrintWriter printWriter = response.getWriter();
printWriter.write("看完博客点赞!");
  • 喜闻可见的事又出现了,我又出现乱码了。

  • 为什么出现乱码了呢?由于Tomcat是外国人的写,Tomcat默认的编码是ISO 8859-1,当我们输出中文数据的时候,Tomcat会依据ISO 8859-1码表给我们的数据编码,中文不支持这个码表呀,所以出现了乱码
  • 既然如此,我设置一下编码不就好了吗,代码如下:


        //原本是ISO 8859-1的编码,我设置成UTF-8
response.setCharacterEncoding("UTF-8"); //获取到printWriter对象
PrintWriter printWriter = response.getWriter();
printWriter.write("看完博客点赞!");
  • 我再访问了一下,我的天!看起来更乱了!

  • 为什么乱码问题还没有解决?细心的朋友会发现,我只是在中文转换的时候把码表设置成UTF-8,但是浏览器未必是使用UTF-8码表来显示数据的呀
  • 好的,我们来看看浏览器的编码格式,果然,浏览器使用GB2312显示UTF-8的数据,不乱码才怪呢

  • 这个问题我们在上面已经是有两种方法解决了【使用标签模拟消息头、设置消息头】,Servlet还提供了一个方法给我们

//设置浏览器用UTF-8编码显示数据
response.setContentType("text/html;charset=UTF-8");
  • 好的,我们再来访问一下

  • 既然Servlet有那么多方法解决乱码问题,是不是有一种是最简便的呢?没错!下面这个方法是最简便的,它不仅设置浏览器用UTF-8显示数据,内部还把中文转码的码表设置成UTF-8了,也就是说,它把response.setCharacterEncoding("UTF-8")的事情也干了!

response.setContentType("text/html;charset=UTF-8");
  • 使用getWriter()显示中文数据,只需要一个方法就搞掂了!

//设置浏览器用UTF-8编码显示数据,
response.setContentType("text/html;charset=UTF-8"); //获取到printWriter对象
PrintWriter printWriter = response.getWriter();
printWriter.write("看完博客点赞!");


实现文件下载

下载资源我们在日常中也很常用,它是怎么做到的呢?要能够给别人下载,服务器就应该有这个资源

  • 现在我web站点下有一个图片了!

  • 既然浏览器发送所有的请求都是去找Servlet的话,那么我就写一个Servlet,当别人访问我这个Servlet的时候,它们就可以下载我这个图片了

  • java的文件上传下载都是通过io流来完成的,既然要下载图片,首先要能够读取到它


//获取到资源的路径
String path = this.getServletContext().getRealPath("/download/1.png"); //读取资源
FileInputStream fileInputStream = new FileInputStream(path); //获取到文件名,路径在电脑上保存是\\形式的。
String fileName = path.substring(path.lastIndexOf("\\") + 1);
  • 告诉浏览器,我要下载这个文件

//设置消息头,告诉浏览器,我要下载1.png这个图片
response.setHeader("Content-Disposition", "attachment; filename="+fileName);
  • 将读取到的内容回送给浏览器

//把读取到的资源写给浏览器
int len = 0;
byte[] bytes = new byte[1024];
ServletOutputStream servletOutputStream = response.getOutputStream(); while ((len = fileInputStream.read(bytes)) > 0) {
servletOutputStream.write(bytes, 0, len);
} //关闭资源
servletOutputStream.close();
fileInputStream.close();
  • 当我访问时,浏览器就提示下载了。

  • 也可以成功打开!

  • 现在问题又有了,如果我文件的名字是中文呢?

  • 我们再访问一下,发现名字乱码了(怎么都是乱码)

  • 为了解决文件名乱码,我们要进行URL编码,代码如下:

response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8"));
  • 再次访问时,文件名乱码问题就解决了!


实现自动刷新

以规定的时间让页面刷新,更新资源

  • 让浏览器实现自动刷新,那肯定又是修改消息头了。

//每3秒自动刷新网页一次
response.setHeader("Refresh", "3");
  • 为了更好的看效果,我们加入时间值进去

response.getWriter().write("time is :" + System.currentTimeMillis());
  • 每三秒时间值就会发生变化

  • 学完上面的,好像没有什么用,自己上网的时候谁看得见这样的东西。自动刷新,能够实现页面的跳转
  • 我们登陆完网站,很多时候都会看见【登陆成功,3秒后自动跳转….】,其实这个就是用Refresh来完成的。

response.setContentType("text/html;charset=UTF-8");
response.getWriter().write("3秒后跳转页面....."); //三秒后跳转到index.jsp页面去,web应用的映射路径我设置成/,url没有写上应用名
response.setHeader("Refresh", "3;url='/index.jsp'");
  • 看下效果


设置缓存

浏览器本身就存在着缓存机制

  • 当我第一次访问index.jsp时,浏览器向服务器发了两次请求【一个是网页的,一个是图片的】

  • 当我第二次访问index.jsp的时候,浏览器将图片缓存起来了!图片不是重新加载的,是从缓存里面取出来的

  • 像股票类型的网页是不能取缓存的数据的,数据都是要不断更新的。下面我就禁止缓存的功能

//浏览器有三消息头设置缓存,为了兼容性!将三个消息头都设置了
response.setDateHeader("Expires", -1);
response.setHeader("Cache-Control","no-cache");
response.setHeader("Pragma", "no-cache"); //这里为了看效果
PrintWriter printWriter = response.getWriter();
printWriter.print("你好啊" + new Date().toString());
  • 当然了,如果页面有些数据不长期更新,你就将它设置成缓存,这样可以提高服务器的性能

实现数据压缩

网页上的信息量是很大的,如果不将数据压缩再回送给浏览器,这样就十分耗费流量

  • 现在我有一篇文章要输出给浏览器
        response.setContentType("text/html;charset=UTF-8");

        String ss = "fsdfhsdfhuisdhfusdhfuids" +
"fsdfdsfsdfsdfdsfdafdsfhsdjfhsdjkfhkjds" +
"fdsfjdslkfjsldkfjsdlkfjsdkfsdjkff" +
"fsjdfjdsklfjdsklfjkldsfjlksdjflksdjflkds" +
"dsjfklsdjflsdjfkldsfkjsdkfjsldkfjsdlfk" +
"fdsjlkfjdslkfjsdlkfjlkasjflk";
response.getWriter().write("原来的长度是:"+ss.getBytes().length+"</br>"); //输出给浏览器
response.getWriter().write(ss);
  • 访问一下可以看到,原来的长度是201

  • 压缩的原理是什么?我们知道getOutputStream()和getWriter()都是直接把数据输出给浏览器的。现在我要做的就是让数据不直接输出给浏览器,先让我压缩了,再输出给浏览器java提供了GZIP压缩类给我们
  • 就让我们使用GZIP类来对数据压缩吧

//GZIP的构造方法需要一个OutputStream子类对象,究竟哪个对象适合,我们看下write()方法
GZIPOutputStream gzipOutputStream = new GZIPOutputStream(); //查看了下API,write()接收的是byte[]类型的。
gzipOutputStream.write();
  • 于是我就在构造函数上传递个ByteArrayOutputStream给它


        //既然是byte[]类型,那么我就给他一个ByteArrayOutputStream
GZIPOutputStream gzipOutputStream = new GZIPOutputStream(new ByteArrayOutputStream());
  • 而用GZIPOutputStream写数据的时候,是把数据写到ByteArrayOutputStream上的,等会还要把数据取出来,再写给浏览器,于是就不能以匿名内部类的方式给GZIPOutputStream,必须把ByteArrayOutputStream定义出来

//创建GZIPOutputStream对象,给予它ByteArrayOutputStream
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
GZIPOutputStream gzipOutputStream = new GZIPOutputStream(byteArrayOutputStream); //GZIP对数据压缩,GZIP写入的数据是保存在byteArrayOutputStream上的
gzipOutputStream.write(ss.getBytes()); //gzipOutputStream有缓冲,把缓冲清了,并顺便关闭流
gzipOutputStream.close();
  • 压缩后的数据取出来,写给浏览器

//将压缩的数据取出来
byte[] bytes = byteArrayOutputStream.toByteArray(); //将压缩的数据写给浏览器
response.getOutputStream().write(bytes);
  • 我们来对比一下压缩前的大小和压缩后的大小

  • 数据的确是压缩了,然而,为什么又乱码了啊?很简单,既然你压缩了数据,你写给浏览器,浏览器是不知道你这是压缩后的数据,它是以正常的方式打开数据的。这当然造成乱码啦!,现在我要告诉浏览器我这是压缩数据

//告诉浏览器这是gzip压缩的数据
response.setHeader("Content-Encoding","gzip"); //再将压缩的数据写给浏览器
response.getOutputStream().write(bytes);
  • 再次访问一下


生出随机图片

生成随机图片这是非常常见的。在我们登陆的时候经常要写验证码,而那些验证码是一张图片,就是通过HttpServletResponse写给浏览器的。


  • 要生成一张图片,java提供了BufferedImage类供我们使用


        //在内存中生成一张图片,宽为80,高为20,类型是RGB
BufferedImage bufferedImage = new BufferedImage(80, 20, BufferedImage.TYPE_INT_RGB); //获取到这张图片
Graphics graphics = bufferedImage.getGraphics(); //往图片设置颜色和字体
graphics.setColor(Color.BLUE);
graphics.setFont(new Font(null, Font.BOLD, 20)); //往图片上写数据,先写个12345,横坐标是0,纵坐标是20【高度】
graphics.drawString("12345", 0, 20);
  • 好的,现在我们在内存中创建了一张图片,并写上了12345。接着,我们要把图片写给浏览器了把图片写给浏览器,java又提供了图片流【ImageIO】给我们使用

//要往浏览器写一张图片,那要告诉浏览器回送的类型是一张图片
response.setHeader("ContentType", "jpeg"); //java提供了图片流给我们使用,这是一个工具类
//把图片传进去,类型是jpg,写给浏览器
ImageIO.write(bufferedImage, "jpg", response.getOutputStream());
  • 我们来访问一下,看下图片长什么样

  • 这样太丑了,我们把背景改成白色看看

//把白色填充整张图片
graphics.setColor(Color.white);
graphics.fillRect(0, 0, 80, 20);
  • 再看看效果,这明显好看多了

  • 好的,我们的图片数字不可能是人工写的,数字应该是随机产生的!这个就简单了。现在我要生成7位的随机数,生成随机数的方法如下


    private String makeNum() {

        Random random = new Random();

        //这样就会生成0-7位的随机数,现在问题又来了,如果随机数不够7位呢?如果不够7位,我们加到7位就行了
int anInt = random.nextInt(9999999); //将数字转成是字符串
String num = String.valueOf(anInt); //判断位数有多少个,不够就加
StringBuffer stringBuffer = new StringBuffer();
for (int i = 0; i < 7 - num.length(); i++) {
stringBuffer.append("0");
} return stringBuffer.append(num).toString(); }
  • 如果要生成中文,就找中文映射表即可

重定向跳转

什么是重定向跳转呢?点击一个超链接,通知浏览器跳转到另外的一个页面就叫重定向跳转。是通知浏览器去跳转,这很重要。页面之间的跳转有两种方式:重定向和转发,至于什么时候用重定向,什么用转发,我在讲完HttpServletRequest对象的时候会详细说明。

  • 我们来使用以下HttpServletResponse对象的重定向

//重定向到index.jsp页面
response.sendRedirect("/zhongfucheng/index.jsp");
  • 浏览器的地址栏访问Servlet222

  • 跳转到index.jsp页面,地址栏发生了变化

  • 我们再来看看http协议发生了什么

  • 从图上看,我们看到了两个状态码,一个是302。一个是200。302状态码在http协议中代表的是临时重定向。举个例子:我找纪律委员说:给我一份请假表,我要回家。纪律委员告诉我:我这里没有请假表,你去找辅导员吧。再看回我访问Sevlet222时:我找Servlet222,Servlet222告诉浏览器:我没有你想要的资源,你要的资源在index.jsp页面中,你自己去找吧。
  • 很容易看出重定向是通过302状态码和跳转地址实现的。于是乎,我们设置http消息头就可以实现重定向跳转

//设置状态码是302
response.setStatus(302); //HttpServletResponse把常用的状态码封装成静态常量了,所以我们可以使用SC_MOVED_TEMPORARILY代表着302
response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); //跳转的地址是index.jsp页面
response.setHeader("Location", "/zhongfucheng/index.jsp");
  • 其实sendRedirect()方法就是对setStatus()和setHeader()进行封装,原理就是setStatus()和setHeader()

getWriter和getOutputStream细节

  1. getWriter()和getOutputStream()两个方法不能同时调用。如果同时调用就会出现异常
  2. Servlet程序向ServletOutputStream或PrintWriter对象中写入的数据将被Servlet引擎从response里面获取,Servlet引擎将这些数据当作响应消息的正文,然后再与响应状态行和各响应头组合后输出到客户端
  3. Servlet的serice()方法结束后【也就是doPost()或者doGet()结束后】,Servlet引擎将检查getWriter或getOutputStream方法返回的输出流对象是否已经调用过close方法,如果没有,Servlet引擎将调用close方法关闭该输出流对象。

Servlet第三篇【request和response简介、response的常见应用】的更多相关文章

  1. Servlet第三篇(response;request)

    response对象 Tomcat收到客户端的http请求,会针对每一次请求,分别创建一个代表请求的request对象.和代表响应的response对象 那么我们获取浏览器提交过来的数据,找reque ...

  2. 第三篇 request篇

    每个框架中都有处理请求的机制(request),但是每个框架的处理方式和机制是不同的 为了了解Flask的request中都有什么东西,首先我们要写一个前后端的交互 基于HTML + Flask 写一 ...

  3. servlet第三篇

    Servlet是一个供其他Java程序(Servlet引擎)调用的Java类,它不能独立运行,它的运行完全由Servlet引擎来控制和调度. 针对客户端的多次Servlet请求,通常情况下,服务器只会 ...

  4. flask第三篇 request

    每个框架中都有处理请求的机制(request),但是每个框架的处理方式和机制是不同的 为了了解Flask的request中都有什么东西,首先我们要写一个前后端的交互 基于HTML + Flask 写一 ...

  5. 第三篇、CSS样式简介

    <!--1.行内样式 <p style="background-color:red;font-size:20px"> --> <!--2.页内样式 & ...

  6. Servlet(三):生命周期、常用方法、常见错误

    Servlet的生命周期:从第一次调用,到服务器关闭.如果在web.xml 中配置了load-on-startup则是从服务器开启到服务器关闭. 注意: * init方法是对Servlet进行初始化的 ...

  7. 第三篇(那些JAVA程序BUG中的常见单词)

    illegal modifier for parameter xxx; only final is permitted 参数xxx的修饰符非法:只允许final illegal 非法的 modifie ...

  8. request和response简介

    Tomcat收到客户端的http请求,会针对每一次请求,分别创建一个代表请求的request对象.和代表响应的response对象. 既然request对象代表http请求,那么我们获取浏览器提交过来 ...

  9. 第三篇——第二部分——第一文 SQL Server镜像简介

    原文:第三篇--第二部分--第一文 SQL Server镜像简介 原文出处:http://blog.csdn.net/dba_huangzj/article/details/26951563 镜像是什 ...

随机推荐

  1. Fiddler模拟重发请求

    在测试的过程中会碰到模拟请求的重发或者修改请求的参数进行请求模拟发送 一.Reissue Sequentially 模拟多次重发 1.启用后fiddler:PC端或手机端创建某条数据后,session ...

  2. MVC项目中使用百度地图

    已经很久没更新博客了,因为最近一直在学习前端的知识,没那么多时间,写博客或者写文章不但没有钱,写得好还好说,如果写得不好,一些吃瓜群众,不仅要喷你,搞不好还要人身攻击就不好了.所以写博客的人,脸皮得厚 ...

  3. 利用OpenCms9提供的模块创建新站点

    OpenCms 9中提供b一个Demo,Demo使用了alkacon的bootstrap模板.如果已经安装了OpenCms 9,可以登陆http://localhost:8080/opencms/op ...

  4. Win10个性化设置

    Win10个性化设置.. ---------------------- Capture001-我的桌面 ---------------------- Win10设置任务栏的颜色 ----------- ...

  5. STL学习之find系列函数

    这里先介绍find, find_if, find_first_of,三个函数.其余的以后再更新. 一.std::find() 用法:find(first, end, value); 返回区间[firs ...

  6. 没有基础如何学习web渗透测试?

    如果只是因为感兴趣玩玩的话,你可以不需要学习太多的脚本程序. 但是以下条件要具备 1.能看懂教程:能理解原理,例如解析漏洞,sql注入逻辑等 2.前端代码审计:html js css 3.主流工具的使 ...

  7. ReactNative环境搭建扩展篇——安装后报错解决方案

    之前一篇写了<逻辑性最强的React Native环境搭建与调试>说了RN的安装,今天在这里做一个复盘,让我们能够更直观更深入的了解React Native(以下简称RN),这一篇重点来说 ...

  8. Windows下JNI的使用教程

    JNI的使用大致有以下4个步骤: 一.在Java中写native方法 二.用javah命令生成C/C++头文件 三.写对应的C/C++程序实现头文件中声明的方法,并编译成库文件 四.在Java中加载这 ...

  9. Servlet与JSP内置对象的对应关系、Servlet获取表单、Servlet路径跳转

    项目的根目录指的是webroot: 服务器内部跳转: 或者使用../:“..”代表回到上一级目录

  10. Celery基本原理探讨

    本文对Celery进行了研究,由于其实现相对比较复杂没有足够的时间和精力对各方各面的源码进行分析,因此本文根据Celery的使用方法以及实际行为分析其运行原理,并根据查阅相关代码进行了一定程度的验证. ...