之前写了我们可以向服务器发送请求,那么服务器自然也可以给我们进行响应
请求有HttpServletRequest来获取,那么数据的响应自然也有一个对象来处理HttpServletResponse,
原理与resquest一样
也是去继承了一个接口,然后服务器给我们做了一个实现类,
在我们实现一个HttpServlet的时候,doPost与doGet方法里面参数传递的是:
HttpServletReponse hsr = new HttpServletResponseWrapper()这个类
OK,现在说一下响应消息的格式,与请求消息一样
这里还不得不说一点,就是响应头的状态码 ,简单来说,就是告诉你你访问的页面现在处于一个什么状态
下面来说,设置状态码,与设置响应头信息,这些都是给客户端看的。
setStatus(一个三位数的响应状态码)
setHeader(String name,String value)
响应是为了给客户端传送数据的,那么我们就需要输出流
上面的流一个是字符流,一个是字节流。
下面直接上代码:
package datatransmisson;
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;
import java.io.PrintWriter;
@WebServlet("/servlet1")
public class ResponseServlet1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//防止写给客户端的数据出现乱码
response.setContentType("text/html;charset=utf-8");
//向客户端回写响应数据
PrintWriter pw = response.getWriter();
char[] buf = {'我','来','了','啊'};
pw.write(buf);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
结果:
也可以通过字节码传输数据
下面说一下重定向,之前说请求的时候,说过一个页面转发,这两者还是有很大区别的。
话不多说,直接上代码
先来看看页面的站内转发
ResponseServlet1
package changedirection;
import javax.servlet.RequestDispatcher;
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;
//从1重定向到2
@WebServlet("/responseServlet1")
public class ResponseServlet1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("i am demo1....");
/*response.setStatus(302);
response.setHeader("location","/response/responseServlet2");*/
//转发
//内部需要一个你要传入到什么位置去的参数实例
RequestDispatcher rd = request.getRequestDispatcher("/responseServlet2");
rd.forward(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
上面的页面会跳转到responseServlet2页面
package changedirection;
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("/responseServlet2")
public class ResponseServlet2 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("i am demo2,.....");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
浏览器显示,无跳转,无变化
上面把demo1与demo2都打印出来了。
下面我们来看页面重定向,修改一下上面的代码
访问ResponseServlet1,直接跳转到ResponseDsevlet2页面。
还可以写成这样
上面需要注意到路径
重定向:
页面跳转:
重定向必须把虚拟目录写才能访问,而内部的资源跳转只需要写上java的映射文件名字
下面来说一下ServletContext对象
代表了整个web应用对象,简单来说,就是它的域是全局的。
我之前说过,一个请求之间,是可以共享数据的,当然是针对于内部服务器资源,一个资源跳转到另外一个资源,可以携带数据过去,但是这两个资源以外的资源想要访问这些数据,是不可以的。但是ServletContext对象就不一样,只要你在一个资源文件中设置了数据,在其他任何一个资源文件,你只要获得这个ServletContext对象就可以,这也说明了这个类的实例化对象是采用的单例设计模式来设计。
话不多说,直接上源代码:
RequestServlet1
package servletcontext;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
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("/requestServlet1")
public class RequestServlet1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//利用request来创造数据
request.setAttribute("name","i am requestServlet1, i will go requestServlet2");
ServletContext sc = request.getServletContext();
//同时设置一个全局属性
sc.setAttribute("where","anywhere");
//我们必须设置页面分发
RequestDispatcher rd = request.getRequestDispatcher("/requestServlet2");
//把request与response带过去
rd.forward(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
RequestServlet2
package servletcontext;
import javax.servlet.ServletContext;
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("/requestServlet2")
public class RequestServlet2 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取Servlet1传递过来的属性值
Object value = request.getAttribute("name");
System.out.println("access the data :"+ value);
//另外有一个全局属性,需要来获取
ServletContext sc = this.getServletContext();
Object value1 = sc.getAttribute("where");
System.out.println(value1);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
然后来看另外一个文件ServletContext1
package servletcontext;
import javax.servlet.ServletContext;
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("/servletContext1")
public class ServletContext1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//整个域数据共享
ServletContext sc = request.getServletContext();
Object res = sc.getAttribute("where");
System.out.println(res);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
运行结果:
下面说一下在ServletContext对象中常用的方法
1.getRealpath("相对路径")-》得到文件真实路径
上面也就是我们真实的项目文件访问路径
2.String getMimeType(String file) 得到互联网一种文件类型,他是大类型包含了小类型,比如text/html,一种文件类型格式,在下载的时候,我们就要指明这种格式
ok,下面说你一个文件下载案例
首先来一个前端展示页面,让用户点击下载
先来看看我的文件结构
资源我放在img目录下面,点击链接,然后去访问一个java文件,然后下载资源,同时传递了一个文件真实名字,注意filename要与文件真实名字一一对应
话不多说,直接上代码
download.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>文件下载页面</title>
</head>
<body>
<a href="/response/downloadServlet?filename=图片.jpg">图片1</a>
<a href="/response/downloadServlet?filename=01.mp4">视频</a>
</body>
</html>
然后看一个下载的java页面
DownloadServlet
package download;
import utils.DownLoadUtils;
import javax.servlet.ServletContext;
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.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
@WebServlet("/downloadServlet")
public class DownloadServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//先把filename拿过来
String filename = request.getParameter("filename");
//下面获取文件在服务器的真实路径
//开发路径与服务器真实路径是不一样,所以必须获取真实的路径
ServletContext sc = request.getServletContext();
String path = sc.getRealPath("/img/" + filename);
//采用字节输入流和响应输出流
FileInputStream fis = new FileInputStream(path);
//得到文件的Mime类型
String mimeType = sc.getMimeType(filename);
//设置响应头类型mime类型,固定步骤
response.setHeader("content-type",mimeType);
//获取请求浏览器
String agent = request.getHeader("user-agent");
//对文件名字进行一个处理,主要是中文文件名字问题不处理就展示不了
filename = DownLoadUtils.getFileName(agent,filename);
//设置下载打开方式,固定步骤
response.setHeader("content-disposition","attachment;filename=" + filename);
//得到响应输出流,输出到客户端
ServletOutputStream sos = response.getOutputStream();
byte[] buffer = new byte[1024];
int res = 0;
while((res = fis.read(buffer)) != -1) {
sos.write(buffer,0,res);
}
fis.close();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
其中有一个不同浏览器处理中文的名字的函数,是通过DownLoadUtils类调用的
这个类里面获取文件名字的方法不用去记,直接用就行,
DownLoadUtils
package utils;
import sun.misc.BASE64Encoder;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
public class DownLoadUtils {
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;
}
}
展示一下
今天就说到这吧。