前后端实现文件下载或浏览
- 背景
- 前端
- 后端java
- 其他
- IO流分两种;字符流&字节流
背景
前端html\js\css,使用a标签或者iframe,笔者使用window.open(url)—重新打开标签页地址栏显示的接口路径;后端返回客户端[HttpServletResponse] 文件流(以附件的方式[attachment]下载,或者在线方式[inline]浏览)。
笔者编译平台为x5,因此调用.j文件才可以使用 HttpServletResponse
前端
var getFileStream = function(subPath, ywlx, operateType) {
console.log("the URL of dzzzRow: "+ subPath);
if (!subPath) return;
var realFileName = subPath.substr(subPath.lastIndexOf("/")+1);
// 提交前需要进行URL转换,在URL上补足bsessionid等必要信息
var url = require.toUrl("$UI/sybdc/service/simpleFileStore.j?bsessionid=" + this.getContext().getBSessionID());
// 用get方式传参
url = url
+ "&subPath=" + subPath
+ "&realFileName=" + realFileName
+ (ywlx? "&ywlx="+ywlx:"")
+ (operateType? "&operateType="+ operateType:"");
window.open(url);
}
// 调用方式:浏览
this.getFileStream(row.val("URL"), "dzzz");
// 调用方式:下载
this.getFileStream(row.val("URL"), "dzzz", "download");
后端java
当ywlx = “dzzz”时,前端传入的路径若文件不存在则会抛异常,读者可根据自己的业务需求另作处理(若文件不存在重新生成文件或者返回前端文件不存在);注意:这里下载与浏览使用的get方式调接口;new File对象并未与磁盘交互,而是在使用File对象的函数(file.exist()、getPath()等等)时才读写磁盘;这里使用的字节文件流
/**
* get为获取文件 浏览或者下载
**/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String operateType = request.getParameter("operateType");
if ("copy".equals(operateType)) {
copyFile(request, response);
} else {
getFile(request, response);
}
}
private static final int BUFFER_SIZE = 32768 * 8;
private static void getFile(HttpServletRequest request, HttpServletResponse response) throws IOException {
String ownerID = request.getParameter("ownerID"); //对应的是表 WW_SLCLB 中的主键clid
String realFileName = URLEncoder.encode(request.getParameter("realFileName"), "utf-8");
String storeFileName = request.getParameter("storeFileName");
String operateType = request.getParameter("operateType");
String subPath = request.getParameter("subPath");
String ywlx = request.getParameter("ywlx");
/* String fileSize = request.getParameter("fileSize"); */
File file = null;
if ("dzzz".equals(ywlx)) {
// D:/wwdzzz/sy_gtj / 2023/6/9/CA50808B97900001CBFC12D84B54AC00/苏(2016)射阳县不动产权第0003129号.pdf
file = new File(dzzzDownloadPath + File.separator + subPath);
} else {
file = new File(docStorePath + (subPath != null ? subPath : "") + File.separator + ownerID + File.separator + storeFileName);
}
if(!file.exists()){
System.out.println(subPath + "--------文件不存在----------");
}
FileInputStream fis = new FileInputStream(file);
response.setHeader("Cache-Control", "pre-check=0, post-check=0, max-age=0");
String fileNameKey = "filename";
if ("download".equals(operateType)) { // 以附件方式下载
response.addHeader("Content-Disposition", "attachment; " + fileNameKey + "=\"" + realFileName + "\"");
} else { // 以在线方式浏览
response.addHeader("Content-Disposition", "inline; " + fileNameKey + "=\"" + realFileName + "\"");
}
OutputStream os = response.getOutputStream();
byte[] buffer = new byte[BUFFER_SIZE];
try {
int read;
while ((read = fis.read(buffer)) != -1) {
os.write(buffer, 0, read);
}
} finally {
fis.close();
}
}
其他
关键点在于文件流的读写,即输入流输出流;
IO流分两种;字符流&字节流
1、什么是流
流是个抽象的概念,是对输入输出设备的抽象,输入流可以看作一个输入通道,输出流可以看作一个输出通道。
输入流是相对程序而言的,外部传入数据给程序需要借助输入流。
输出流是相对程序而言的,程序把数据传输到外部需要借助输出流。
2、字节流与字符流
字节流是由字节组成的,字符流是由字符组成的
网络传输的都是二级制数据,字符流又不是二级制,那么不论对方是怎么处理的文件,他最终传给我的一定是字节流
直接使用字节流保存
// 获取一个浏览器
DefaultHttpClient httpclient = new DefaultHttpClient();
// 获取get请求
HttpGet httpget = new HttpGet(url);
// 请求对方服务器
HttpResponse response = httpclient.execute(httpget);
// 获取返回数据
InputStream inputStream = response.getEntity().getContent();
// new 一个本地文件
File file = new File("D:\\11111.pdf");
// 创建相对于程序的输出流
OutputStream outputStream = null;
try {
outputStream = new FileOutputStream(file);
// 读取数据
byte[] b = new byte[1024];// b - 数据
int off = 0;// off - 数据中的起始偏移量。
int len = -1;// len - 要写入的字节数。
while ((len = inputStream.read(b)) != -1) {// 从输入流读取一些字节数,并将它们存储到缓冲区b。实际读取的字节数作为整数返回,如果没有字节可用,因为流在文件末尾,则返回值-1;否则,读取至少一个字节并存储到b。
outputStream.write(b, off, len);// 数组b中的一些字节按顺序写入输出流; 元素off是写入的第一个字节,len是此操作写入的最后一个字节。
}
outputStream.flush();// 刷新此输出流并强制任何缓冲的输出字节被写出。
} catch (IOException e) {
System.out.println("异常");
e.printStackTrace();
} finally {
inputStream.close();//关闭此输入流并释放与此流相关联的任何系统资源。
outputStream.close();//关闭此输出流并释放与此流相关联的任何系统资源。
}
使用字符流或者其他子类详情参考:
链接: 接口返回流并保存本地
java IO选择流的原则及其与IO流相关类的关系
JAVA基础知识之BufferedReader流