mirror of
https://gitee.com/kekingcn/file-online-preview.git
synced 2026-03-14 21:23:47 +08:00
1.修复压缩包 二级目录无法解压问题 修改压缩包生成PDF路径
2.修复PDF 带密码缓存问题 新增PDF带密码缓存方法 userToken 3.精简OFFICE 转换代码 4.精简TIF转换代码 新增TIF转换图片缓存 修复tif错误文件不自动释放内存 等待其他修复 5.修复下载方法错 特殊符号下载错误 6.调整文件名 统一方法在FileHandlerService 7.新增判断文件名是否被URL转义
This commit is contained in:
@@ -1,26 +1,26 @@
|
||||
package cn.keking.utils;
|
||||
|
||||
|
||||
import cn.keking.config.ConfigConstants;
|
||||
|
||||
import com.sun.media.jai.codec.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import cn.keking.web.filter.BaseUrlFilter;
|
||||
import com.itextpdf.text.Document;
|
||||
import com.itextpdf.text.Image;
|
||||
import com.itextpdf.text.io.FileChannelRandomAccessSource;
|
||||
import com.itextpdf.text.pdf.PdfWriter;
|
||||
import com.itextpdf.text.pdf.RandomAccessFileOrArray;
|
||||
import com.itextpdf.text.pdf.codec.TiffImage;
|
||||
import com.sun.media.jai.codec.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.media.jai.JAI;
|
||||
import javax.media.jai.RenderedOp;
|
||||
import java.awt.image.RenderedImage;
|
||||
import java.awt.image.renderable.ParameterBlock;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -28,7 +28,6 @@ public class ConvertPicUtil {
|
||||
|
||||
private static final int FIT_WIDTH = 500;
|
||||
private static final int FIT_HEIGHT = 900;
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(ConvertPicUtil.class);
|
||||
private final static String fileDir = ConfigConstants.getFileDir();
|
||||
/**
|
||||
@@ -38,17 +37,14 @@ public class ConvertPicUtil {
|
||||
* @param strOutputFile 输出文件的路径和文件名
|
||||
* @return boolean 是否转换成功
|
||||
*/
|
||||
public static List<String> convertTif2Jpg(String strInputFile, String strOutputFile) {
|
||||
public static List<String> convertTif2Jpg(String strInputFile, String strOutputFile, boolean forceUpdatedCache) throws Exception {
|
||||
List<String> listImageFiles = new ArrayList<>();
|
||||
|
||||
if (strInputFile == null || "".equals(strInputFile.trim())) {
|
||||
return null;
|
||||
}
|
||||
String baseUrl = BaseUrlFilter.getBaseUrl();
|
||||
if (!new File(strInputFile).exists()) {
|
||||
logger.info("找不到文件【" + strInputFile + "】");
|
||||
return null;
|
||||
}
|
||||
strInputFile = strInputFile.replaceAll("\\\\", "/");
|
||||
strOutputFile = strOutputFile.replaceAll(".jpg", "");
|
||||
FileSeekableStream fileSeekStream = null;
|
||||
try {
|
||||
JPEGEncodeParam jpegEncodeParam = new JPEGEncodeParam();
|
||||
@@ -58,20 +54,18 @@ public class ConvertPicUtil {
|
||||
fileSeekStream = new FileSeekableStream(strInputFile);
|
||||
ImageDecoder imageDecoder = ImageCodec.createImageDecoder("TIFF", fileSeekStream, null);
|
||||
int intTifCount = imageDecoder.getNumPages();
|
||||
logger.info("该tif文件共有【" + intTifCount + "】页");
|
||||
String strJpgPath = fileDir+strOutputFile;
|
||||
// logger.info("该tif文件共有【" + intTifCount + "】页");
|
||||
// 处理目标文件夹,如果不存在则自动创建
|
||||
File fileJpgPath = new File(strJpgPath);
|
||||
File fileJpgPath = new File(strOutputFile);
|
||||
if (!fileJpgPath.exists() && !fileJpgPath.mkdirs()) {
|
||||
logger.error("{} 创建失败", strJpgPath);
|
||||
logger.error("{} 创建失败", strOutputFile);
|
||||
}
|
||||
// 循环,处理每页tif文件,转换为jpg
|
||||
for (int i = 0; i < intTifCount; i++) {
|
||||
String strJpg= strJpgPath + "/" + i + ".jpg";
|
||||
String strJpgUrl = strOutputFile + "/" + i + ".jpg";
|
||||
String strJpg= strOutputFile + "/" + i + ".jpg";
|
||||
File fileJpg = new File(strJpg);
|
||||
// 如果文件不存在,则生成
|
||||
if (!fileJpg.exists()) {
|
||||
if (forceUpdatedCache|| !fileJpg.exists()) {
|
||||
RenderedImage renderedImage = imageDecoder.decodeAsRenderedImage(i);
|
||||
ParameterBlock pb = new ParameterBlock();
|
||||
pb.addSource(renderedImage);
|
||||
@@ -80,24 +74,22 @@ public class ConvertPicUtil {
|
||||
pb.add(jpegEncodeParam);
|
||||
RenderedOp renderedOp = JAI.create("filestore", pb);
|
||||
renderedOp.dispose();
|
||||
logger.info("每页分别保存至: " + fileJpg.getCanonicalPath());
|
||||
// logger.info("每页分别保存至: " + fileJpg.getCanonicalPath());
|
||||
}
|
||||
listImageFiles.add(strJpgUrl);
|
||||
strJpg = baseUrl+strJpg.replace(fileDir, "");
|
||||
listImageFiles.add(strJpg);
|
||||
}
|
||||
|
||||
return listImageFiles;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
if (!e.getMessage().contains("Bad endianness tag (not 0x4949 or 0x4d4d)") ) {
|
||||
logger.error("TIF转JPG异常,文件路径:" + strInputFile, e);
|
||||
}
|
||||
throw new Exception(e);
|
||||
} finally {
|
||||
if (fileSeekStream != null) {
|
||||
try {
|
||||
fileSeekStream.close();
|
||||
} catch (IOException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
fileSeekStream.close();
|
||||
}
|
||||
}
|
||||
return listImageFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -106,44 +98,41 @@ public class ConvertPicUtil {
|
||||
* @param strJpgFile 输入的jpg的路径和文件名
|
||||
* @param strPdfFile 输出的pdf的路径和文件名
|
||||
*/
|
||||
public static boolean convertJpg2Pdf(String strJpgFile, String strPdfFile) {
|
||||
Document document = null;
|
||||
public static String convertJpg2Pdf(String strJpgFile, String strPdfFile) throws Exception {
|
||||
Document document = new Document();
|
||||
RandomAccessFileOrArray rafa = null;
|
||||
FileOutputStream outputStream = null;
|
||||
try {
|
||||
document = new Document();
|
||||
PdfWriter.getInstance(document, Files.newOutputStream(Paths.get(strPdfFile)));
|
||||
document.open();
|
||||
rafa = new RandomAccessFileOrArray(new FileChannelRandomAccessSource(new RandomAccessFile(strJpgFile, "r").getChannel()));
|
||||
RandomAccessFile aFile = new RandomAccessFile(strJpgFile, "r");
|
||||
FileChannel inChannel = aFile.getChannel();
|
||||
FileChannelRandomAccessSource fcra = new FileChannelRandomAccessSource(inChannel);
|
||||
rafa = new RandomAccessFileOrArray(fcra);
|
||||
int pages = TiffImage.getNumberOfPages(rafa);
|
||||
outputStream = new FileOutputStream(strPdfFile);
|
||||
PdfWriter.getInstance(document, outputStream);
|
||||
document.open();
|
||||
Image image;
|
||||
for (int i = 1; i <= pages; i++) {
|
||||
try {
|
||||
image = TiffImage.getTiffImage(rafa, i);
|
||||
image.scaleToFit(FIT_WIDTH, FIT_HEIGHT);
|
||||
document.add(image);
|
||||
} catch (Exception e) {
|
||||
document.close();
|
||||
rafa.close();
|
||||
e.printStackTrace();
|
||||
}
|
||||
image = TiffImage.getTiffImage(rafa, i);
|
||||
image.scaleToFit(FIT_WIDTH, FIT_HEIGHT);
|
||||
document.add(image);
|
||||
}
|
||||
document.close();
|
||||
rafa.close();
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
logger.error("图片转PDF异常,图片文件路径:" + strJpgFile, e);
|
||||
} catch (IOException e) {
|
||||
if (!e.getMessage().contains("Bad endianness tag (not 0x4949 or 0x4d4d)") ) {
|
||||
logger.error("TIF转JPG异常,文件路径:" + strPdfFile, e);
|
||||
}
|
||||
throw new Exception(e);
|
||||
} finally {
|
||||
try {
|
||||
if (document != null && document.isOpen()) {
|
||||
document.close();
|
||||
}
|
||||
if (rafa != null) {
|
||||
rafa.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
if (document != null) {
|
||||
document.close();
|
||||
}
|
||||
if (rafa != null) {
|
||||
rafa.close();
|
||||
}
|
||||
if (outputStream != null) {
|
||||
outputStream.close();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return strPdfFile;
|
||||
}
|
||||
}
|
||||
@@ -8,24 +8,27 @@ import io.mola.galimatias.GalimatiasParseException;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.client.RequestCallback;
|
||||
import org.springframework.web.client.RestClientException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import static cn.keking.utils.KkFileUtils.isFtpUrl;
|
||||
import static cn.keking.utils.KkFileUtils.isHttpUrl;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.client.RequestCallback;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* @author yudian-it
|
||||
*/
|
||||
@@ -46,6 +49,7 @@ public class DownloadUtils {
|
||||
* @return 本地文件绝对路径
|
||||
*/
|
||||
public static ReturnResponse<String> downLoad(FileAttribute fileAttribute, String fileName) {
|
||||
String fileKey = fileAttribute.getFileKey();
|
||||
// 忽略ssl证书
|
||||
String urlStr = null;
|
||||
try {
|
||||
@@ -70,8 +74,7 @@ public class DownloadUtils {
|
||||
response.setMsg("下载失败:不支持的类型!" + urlStr);
|
||||
return response;
|
||||
}
|
||||
assert urlStr != null;
|
||||
if (urlStr.contains("?fileKey=")) {
|
||||
if (!ObjectUtils.isEmpty(fileKey)) { //压缩包文件 直接赋予路径 不予下载
|
||||
response.setContent(fileDir + fileName);
|
||||
response.setMsg(fileName);
|
||||
return response;
|
||||
@@ -87,20 +90,37 @@ public class DownloadUtils {
|
||||
if (!fileAttribute.getSkipDownLoad()) {
|
||||
if (isHttpUrl(url)) {
|
||||
File realFile = new File(realPath);
|
||||
SimpleClientHttpRequestFactory httpFactory = new SimpleClientHttpRequestFactory();
|
||||
//连接超时10秒,默认无限制,单位:毫秒
|
||||
httpFactory.setConnectTimeout(60 * 1000);
|
||||
//读取超时5秒,默认无限限制,单位:毫秒
|
||||
httpFactory.setReadTimeout(60 * 1000);
|
||||
restTemplate.setRequestFactory(httpFactory);
|
||||
RequestCallback requestCallback = request -> {
|
||||
request.getHeaders()
|
||||
.setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL));
|
||||
String proxyAuthorization = fileAttribute.getKkProxyAuthorization();
|
||||
request.getHeaders().setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL));
|
||||
String proxyAuthorization = fileAttribute.getKkProxyAuthorization();
|
||||
if(StringUtils.hasText(proxyAuthorization)){
|
||||
Map<String,String> proxyAuthorizationMap = mapper.readValue(proxyAuthorization, Map.class);
|
||||
proxyAuthorizationMap.entrySet().forEach(entry-> request.getHeaders().set(entry.getKey(), entry.getValue()));
|
||||
Map<String,String> proxyAuthorizationMap = mapper.readValue(proxyAuthorization, Map.class);
|
||||
proxyAuthorizationMap.forEach((key, value) -> request.getHeaders().set(key, value));
|
||||
}
|
||||
};
|
||||
urlStr = URLDecoder.decode(urlStr, StandardCharsets.UTF_8.name());
|
||||
restTemplate.execute(urlStr, HttpMethod.GET, requestCallback, fileResponse -> {
|
||||
FileUtils.copyToFile(fileResponse.getBody(), realFile);
|
||||
return null;
|
||||
});
|
||||
try {
|
||||
URI uri = URI.create(urlStr);
|
||||
restTemplate.execute(uri, HttpMethod.GET, requestCallback, fileResponse -> {
|
||||
FileUtils.copyToFile(fileResponse.getBody(), realFile);
|
||||
return null;
|
||||
});
|
||||
} catch (RestClientException e) {
|
||||
if (e.getMessage().contains("404 Not Found") || e.getMessage().contains("403 Not Found") || e.getMessage().contains("500 Not Found") ){
|
||||
response.setCode(1);
|
||||
response.setContent(null);
|
||||
response.setMsg("下载失败:" + e);
|
||||
return response;
|
||||
}else {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
} else if (isFtpUrl(url)) {
|
||||
String ftpUsername = WebUtils.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_USERNAME);
|
||||
String ftpPassword = WebUtils.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_PASSWORD);
|
||||
|
||||
82
server/src/main/java/cn/keking/utils/UrlEncoderUtils.java
Normal file
82
server/src/main/java/cn/keking/utils/UrlEncoderUtils.java
Normal file
@@ -0,0 +1,82 @@
|
||||
package cn.keking.utils;
|
||||
import java.util.BitSet;
|
||||
|
||||
|
||||
public class UrlEncoderUtils {
|
||||
|
||||
private static BitSet dontNeedEncoding;
|
||||
|
||||
static {
|
||||
dontNeedEncoding = new BitSet(256);
|
||||
int i;
|
||||
for (i = 'a'; i <= 'z'; i++) {
|
||||
dontNeedEncoding.set(i);
|
||||
}
|
||||
for (i = 'A'; i <= 'Z'; i++) {
|
||||
dontNeedEncoding.set(i);
|
||||
}
|
||||
for (i = '0'; i <= '9'; i++) {
|
||||
dontNeedEncoding.set(i);
|
||||
}
|
||||
dontNeedEncoding.set('+');
|
||||
/**
|
||||
* 这里会有误差,比如输入一个字符串 123+456,它到底是原文就是123+456还是123 456做了urlEncode后的内容呢?<br>
|
||||
* 其实问题是一样的,比如遇到123%2B456,它到底是原文即使如此,还是123+456 urlEncode后的呢? <br>
|
||||
* 在这里,我认为只要符合urlEncode规范的,就当作已经urlEncode过了<br>
|
||||
* 毕竟这个方法的初衷就是判断string是否urlEncode过<br>
|
||||
*/
|
||||
|
||||
dontNeedEncoding.set('-');
|
||||
dontNeedEncoding.set('_');
|
||||
dontNeedEncoding.set('.');
|
||||
dontNeedEncoding.set('*');
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断str是否urlEncoder.encode过<br>
|
||||
* 经常遇到这样的情况,拿到一个URL,但是搞不清楚到底要不要encode.<Br>
|
||||
* 不做encode吧,担心出错,做encode吧,又怕重复了<Br>
|
||||
*
|
||||
* @param str
|
||||
* @return
|
||||
*/
|
||||
public static boolean hasUrlEncoded(String str) {
|
||||
|
||||
/**
|
||||
* 支持JAVA的URLEncoder.encode出来的string做判断。 即: 将' '转成'+' <br>
|
||||
* 0-9a-zA-Z保留 <br>
|
||||
* '-','_','.','*'保留 <br>
|
||||
* 其他字符转成%XX的格式,X是16进制的大写字符,范围是[0-9A-F]
|
||||
*/
|
||||
boolean needEncode = false;
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
char c = str.charAt(i);
|
||||
if (dontNeedEncoding.get((int) c)) {
|
||||
continue;
|
||||
}
|
||||
if (c == '%' && (i + 2) < str.length()) {
|
||||
// 判断是否符合urlEncode规范
|
||||
char c1 = str.charAt(++i);
|
||||
char c2 = str.charAt(++i);
|
||||
if (isDigit16Char(c1) && isDigit16Char(c2)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// 其他字符,肯定需要urlEncode
|
||||
needEncode = true;
|
||||
break;
|
||||
}
|
||||
|
||||
return !needEncode;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断c是否是16进制的字符
|
||||
*
|
||||
* @param c
|
||||
* @return
|
||||
*/
|
||||
private static boolean isDigit16Char(char c) {
|
||||
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user