需求
项目需要打印文档及图片,文件在远程文件服务器上
实现逻辑
1. 读取远程url将其转为输入流
2. 设置HttpServletResponse相关参数,将输入流转为文件流输出,支持预览
3. 2中的url在浏览器中已经可以直接预览,但是Chrome浏览器PDF查看器预览和下载使用的同一个链接,请求头不同导致下载失效。因此,此处引入pdfjs插件实现pdf预览
代码
java代码
@RequestMapping("/preview")
public void preview(HttpServletResponse response) {
// 模拟文件存放与文件服务器的情况
URL url = this.getClass().getClassLoader().getResource("static/OpenOffice安装.pdf");
String fileExt = FileUtils.getFileExt(url.getPath());
response.reset();
response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
response.setCharacterEncoding("utf-8");
response.setContentType(MimeTypeEnum.getMimeType(fileExt));
response.setHeader("Content-Disposition", "inline;filename=file." + fileExt);
response.setDateHeader("expries", -1);
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");
response.setHeader("Access-Control-Allow-Origin", "*");
try (
ServletOutputStream os = response.getOutputStream();
InputStream is = FileUtils.readUrl(url)
) {
os.write(FileUtils.streamToBytes(is));
os.flush();
} catch (Exception e) {
throw new CommonException("预览失败");
}
}
package com.fh.hzbase.utils;
import com.fh.hzbase.bean.CommonException;
import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
/**
* 文件工具类
*/
public class FileUtils {
/**
* 读取url
*
* @param urlStr
* @return
*/
public static InputStream readUrl(String urlStr) {
try {
URL url = new URL(urlStr);
URLConnection connection = url.openConnection();
connection.setConnectTimeout(10 * 1000);
return connection.getInputStream();
} catch (Exception e){
throw new CommonException("读取文件失败", e);
}
}
public static InputStream readUrl(URL url ) {
try {
URLConnection connection = url.openConnection();
connection.setConnectTimeout(10 * 1000);
return connection.getInputStream();
} catch (Exception e){
throw new CommonException("读取文件失败", e);
}
}
public static byte[] streamToBytes(InputStream is) {
try(ByteOutputStream bos = new ByteOutputStream()) {
int len;
byte[] buf = new byte[1024];
while ((len = is.read(buf)) != -1) {
bos.write(buf, 0, len);
}
return bos.getBytes();
} catch (IOException e) {
throw new CommonException("读取流失败", e);
}
}
public static String getFileExt(String fileName) {
return fileName.substring(fileName.lastIndexOf(".") + 1);
}
}
package com.fh.hzbase.bean;
/**
* @description:
* @author: pp_lan
* @date: 2022/3/17 10:14
*/
public class CommonException extends RuntimeException {
public CommonException() {
}
public CommonException(String message) {
super(message);
}
public CommonException(String message, Throwable cause) {
super(message, cause);
}
public CommonException(Throwable cause) {
super(cause);
}
public CommonException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
前端代码
<!DOCTYPE html>
<html xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8">
<title>预览示例</title>
</head>
<body>
<div id="app">
<button v-on:click="preview">预览</button>
</div>
</body>
<script type="text/javascript" src="./js/vue.js"></script>
<script type="text/javascript">
var app = new Vue({
el: "#app",
data: {
},
methods: {
preview: function() {
var baseUrl = 'http://localhost:8080';
//window.open(baseUrl + '/pdfjs/web/viewer.html?file=' + encodeURIComponent(baseUrl + '/OpenOffice安装.pdf'));
window.open(baseUrl + '/pdfjs/web/viewer.html?file=' + encodeURIComponent(baseUrl + '/store/preview'));
}
},
mounted: function () {
},
beforeDestroy: function () {
}
});
</script>
</html>
实现效果
总结:
1. 在要求简单的情况下,直接使用文件流(第2步),可以直接预览(缺点:Chrome自带的pdf查看器,点击下载会下载失败)
2. 要规避上述问题,可以引入pdfjs插件,并且可以自己定义和屏蔽功能