Response设置响应数据
Reponse的继承体系和Request的继承体系非常相似:
我们使用的也是ResponseFacade实现类,所以用法与前文的Request差不多
Response请求重定向
Response重定向(redirect):一种资源跳转方式。
实现过程:
(1)浏览器发送请求给服务器,服务器中对应的资源A接收到请求
(2)资源A现在无法处理该请求,就会给浏览器响应一个302的状态码+location的一个访问资源B的路径
(3)浏览器接收到响应状态码为302就会重新发送请求到location对应的访问地址去访问资源B
(4)资源B接收到请求后进行处理并最终给浏览器响应结果,这整个过程就叫重定向
实现方式:
①普通方式
resp.setStatus(302);
resp.setHeader("location","资源B的访问路径");
②简便方式
resposne.sendRedirect("资源B的访问路径");
我们还是通过一个例子去理解它:
(1)创建ResponseDemo1类
@WebServlet("/resp1")
public class ResponseDemo1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("resp1....");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
(2)创建ResponseDemo2类
@WebServlet("/resp2")
public class ResponseDemo2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("resp2....");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
(3)在ResponseDemo1的doGet方法中给前端响应数据
@WebServlet("/resp1")
public class ResponseDemo1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("resp1....");
//重定向
//1.设置响应状态码 302
response.setStatus(302);
//2. 设置响应头 Location
response.setHeader("Location","/request-demo/resp2");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
(4)启动测试
访问http://localhost:8080/request-demo/resp1
,就可以在控制台看到如下内容:
resp1...
resp2...
说明/resp1
和/resp2
都被访问到了。到这重定向就已经完成了。
重定向的特点
-
浏览器地址栏路径发送变化
当进行重定向访问的时候,由于是由浏览器发送的两次请求,所以地址会发生变化
-
可以重定向到任何位置的资源(服务内容、外部均可)
因为第一次响应结果中包含了浏览器下次要跳转的路径,所以这个路径是可以任意位置资源。
-
两次请求,不能在多个资源使用request共享数据
因为浏览器发送了两次请求,是两个不同的request对象,就无法通过request对象进行共享数据
我们可以看看重定向与请求转发的对比:
附:路径问题
问题1:转发的时候路径上没有加/request-demo
而重定向加了,那么到底什么时候需要加,什么时候不需要加呢?
其实判断的依据很简单,只需要记住下面的规则即可:
- 浏览器使用:需要加虚拟目录(项目访问路径)
- 服务端使用:不需要加虚拟目录
对于转发来说,因为是在服务端进行的,所以不需要加虚拟目录
对于重定向来说,路径最终是由浏览器来发送请求,就需要添加虚拟目录。
掌握了这个规则,我么可以来看几个例子:
<a href='路劲'>
<form action='路径'>
- req.getRequestDispatcher(“路径”)
- resp.sendRedirect(“路径”)
答案:
1.超链接,从浏览器发送,需要加
2.表单,从浏览器发送,需要加
3.转发,是从服务器内部跳转,不需要加
4.重定向,是由浏览器进行跳转,需要加。
2问题2:在重定向的代码中,/request-demo
是固定编码的,如果后期通过Tomcat插件配置了项目的访问路径,那么所有需要重定向的地方都需要重新修改,该如何优化?
答案也比较简单,我们可以在代码中动态去获取项目访问的虚拟目录,具体如何获取,我们可以借助前面咱们所学习的request对象中的getContextPath()方法,修改后的代码如下:
@WebServlet("/resp1")
public class ResponseDemo1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("resp1....");
//简化方式完成重定向
//动态获取虚拟目录
String contextPath = request.getContextPath();
response.sendRedirect(contextPath+"/resp2");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
重新启动访问测试,功能依然能够实现,此时就可以动态获取项目访问的虚拟路径,从而降低代码的耦合度。
Response响应字符数据
要想将字符数据写回到浏览器,我们需要两个步骤:
-
通过Response对象获取字符输出流: PrintWriter writer = resp.getWriter();
-
通过字符输出流写数据: writer.write(“aaa”);
接下来我们通过三个场景去进行实验:
①返回一个简单的字符串aaa
/**
* 响应字符数据:设置字符数据的响应体
*/
@WebServlet("/resp3")
public class ResponseDemo3 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
//1. 获取字符输出流
PrintWriter writer = response.getWriter();
writer.write("aaa");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
②返回一串html字符串,并且能被浏览器解析
如果直接写出html是不会被浏览器解析的,此时我们就需要设置响应头中的content-type,使html能被识别
PrintWriter writer = response.getWriter();
//content-type,告诉浏览器返回的数据类型是HTML类型数据,这样浏览器才会解析HTML标签
response.setHeader("content-type","text/html");
writer.write("<h1>aaa</h1>");
③返回一个中文的字符串你好
我们要注意乱码的问题,所以在返回中文的时候,要进行字符集的设置
//设置响应的数据格式及数据的编码
response.setContentType("text/html;charset=utf-8");
writer.write("你好");
setContentType方法有多种作用,我们既可以用它来设置请求头中的content-type也可以用它来设置字符集。
注意:一次请求响应结束后,response对象就会被销毁掉,所以不要手动关闭流。
Response响应字节数据
要想将字节数据写回到浏览器,我们需要两个步骤:
-
通过Response对象获取字节输出流:ServletOutputStream outputStream = resp.getOutputStream();
-
通过字节输出流写数据: outputStream.write(字节数据);
接下来,我们实现通过一个案例加深理解:
- 返回一个图片文件到浏览器
/**
* 响应字节数据:设置字节数据的响应体
*/
@WebServlet("/resp4")
public class ResponseDemo4 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1. 读取文件
FileInputStream fis = new FileInputStream("d://a.jpg");
//2. 获取response字节输出流
ServletOutputStream os = response.getOutputStream();
//3. 完成流的copy
byte[] buff = new byte[1024];
int len = 0;
while ((len = fis.read(buff))!= -1){
os.write(buff,0,len);
}
fis.close();
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
上述代码中,对于流的copy的代码还是比较复杂的,所以我们可以使用别人提供好的方法来简化代码的开发,具体的步骤是:
(1)pom.xml添加依赖
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
(2)调用工具类方法
//fis:输入流
//os:输出流
IOUtils.copy(fis,os);
优化后的代码:
/**
* 响应字节数据:设置字节数据的响应体
*/
@WebServlet("/resp4")
public class ResponseDemo4 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1. 读取文件
FileInputStream fis = new FileInputStream("d://a.jpg");
//2. 获取response字节输出流
ServletOutputStream os = response.getOutputStream();
//3. 完成流的copy
IOUtils.copy(fis,os);
fis.close();
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
附:图片资源定位
在实际项目中我们网站的图片一般是不会和项目放在一起的,这样会增加项目的体积,并且路径也不好写,可以放在服务器的某一个文件夹中。
但是如果我们把图片放在项目当中那么怎么去定位呢?
首先我们要知道通过流去加载图片的路径和我们当前类的加载路径是不一样的。也就是说我们通过class.getClassLoader().getResource()
得到的并不是图片的加载路径。
当然我们可以通过类加载器得到一个输入流,也就是通过getResourceAsStream()拿到类加载器的加载地址,然后我们再去通过这个地址推断图片的相对路径进行加载。
例如:
我们在当前类加载路径上放一个图片:
然后然后我们通过如下的语句也能得到图片的输入流:
IOUtils.class.getClassLoader().getResourceAsStream("haha4.png")
这个资源加载路径应该是和File的路径对应的。
也就是说我们可以通过File.getAbsolutePath()去获得当前文件加载的绝对路径,然后由此来推断图片资源的相对路径。而File类的加载路径其相对路径一般是从项目的内容根开始的。
我们可以推断出一个结论:
相对路径的参考对象并不一定是当前文件对象
我们来看两个例子:
对于web_try这个项目来说,此时我们在IDEA中使用Maven的tomcat插件运行,那么项目的内容根就是src,而我们如果要定位到haha4.png这个图片的话,我们就要使用如下的相对路径:
src\main\webapp\pic\haha4.png
而如果我们把这个项目打成war包,放在tomcat上运行,那么我们的路径就不能这么写,项目结构此时如下:
此时我们的内容根就是这个web_try文件夹,而如果我们要定位到图片资源,那么相对路径就为:
pic/haha4.png
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/122146.html