java之-文件预览终极解决方案
文件预览终极解决方案
在Java中实现文件预览功能需要结合多种技术,具体取决于文件类型(如文档、图片、视频等)。
一:使用统一转成pdf文件进行预览
以下为代码实现步骤
LibreOfficeFileTypeEnum文件枚举
public enum LibreOfficeFileTypeEnum {DOC,DOCX,XLS,XLSX,TXT,PPT,PPTX,HTML;public static boolean isTransformFileType(String fileType) {for (LibreOfficeFileTypeEnum e : LibreOfficeFileTypeEnum.values()) {if (fileType.toUpperCase().equals(e.toString().toUpperCase())) {return true;}}return false;}public static boolean isExcel(String fileType) {if (fileType.toUpperCase().equals(XLS.toString().toUpperCase())||fileType.toUpperCase().equals(XLSX.toString().toUpperCase())) {return true;}return false;}
}
JodConverterSupportOutputType
public enum JodConverterSupportOutputType {HTML(".html"),PDF(".pdf"),PNG(".png");private String value;JodConverterSupportOutputType(String value){this.value = value;}public String getValue(){return this.value;}}
控制层代码
@GetMapping("/{id}")@ApiOperation(value = "文件预览接口", notes = "office文件转成pdf显示,图片文件不变", httpMethod = "GET")public void previews(@PathVariable String id,@RequestParam(value = "size",required = false) String size,@RequestParam(required = false) String resourceGuardToken,HttpServletResponse response) throws IOException{// 检查参数if (StringUtils.isEmpty(id)) {throw ProblemSolver.client(ProblemCode.FILE_DOWNLOAD_LESS_FILE_ID).build();}// 获取文件的基本信息Optional<Object> dbobj= db.get(id);if (!dbobj.isPresent()) {throw ProblemSolver.client(ProblemCode.FILE_DOWNLOAD_FILE_ID_NO_INFO).build();}FileInformation fileInformation = db.get();// 文件类型String[] fileNameSplit = dbobj.getName().split("\\.");if (fileNameSplit.length < 2) {log.error("文件缺少文件类型");throw ProblemSolver.server(ProblemCode.FILE_PREVIEW_MISS_FILE_TYPE).build();}// 文件后缀名String fileType = fileNameSplit[fileNameSplit.length - 1];@Cleanup InputStream fileInputStream = null;File sourceFile = fileInformationService.getFile(fileInformation);try {if (LibreOfficeFileTypeEnum.isTransformFileType(fileType)) {JodConverterSupportOutputType type = JodConverterSupportOutputType.PDF;String contentType = "application/pdf";if (LibreOfficeFileTypeEnum.isExcel(fileType)){type = JodConverterSupportOutputType.HTML;contentType = "text/html";}// sourceFile本地存储时没有后缀名,转换成pdf文件File targetFile = officeFileService.toTargetType(sourceFile,fileUploadConfig.getBasePath(),fileInformation.getName(), type);fileInputStream = new FileInputStream(targetFile);// 指明response的返回对象是pdf文件流response.setContentType(contentType);// 发送文件流sendFileStream(response, fileInputStream);fileInputStream.close();DocumentUtils.emptyFolder(targetFile.getParent());} else if (ImgUtils.isImage(sourceFile,fileInformation.getContentType())) {// 图片文件File targetFile = fileInformationService.imgFilePixelTransition(fileInformation, size);fileInputStream = new FileInputStream(targetFile);response.setContentType(fileInformation.getContentType());// 发送文件流sendFileStream(response, fileInputStream);} else {fileInputStream = new FileInputStream(sourceFile);String contentType = fileInformation.getContentType();if (FileUtils.isPdf(fileType)) {contentType = "application/pdf";}response.setContentType(contentType);// 发送文件流sendFileStream(response, fileInputStream);}} catch (FileNotFoundException e) {log.error("文件不存在",e);throw ProblemSolver.server(ProblemCode.FILE_NOT_FOUND).withStatus(Status.NOT_FOUND).build();} catch (IOException e) {log.error("IO出错",e);throw ProblemSolver.server(ProblemCode.FILE_PREVIEW_IO_ERROR).build();}}
获取文件信息并且创建
public File getFile(FileInformation fileInformation){String fileBasePath = fileUploadConfig.getBasePath();StringBuffer stringBuffer = new StringBuffer();String filePath = stringBuffer.append(fileBasePath).append(fileInformation.getPath()).toString();File file = new File(filePath);if (!file.exists()){log.error("文件无法找到:"+filePath);throw ProblemSolver.server(ProblemCode.FILE_NOT_FOUND).withStatus(Status.NOT_FOUND).build();}return file;}
sourceFile本地存储时没有后缀名,转换成pdf文件
/*** 本地保存的文件没有后缀名,需要给文件重命名* office相关文件转换成pdf/html/png的文件* @param sourceFile 无后缀名的源文件* @param basePath 指定临时文件保存路径* @param sourceFileName 源文件名* @param type 转换文件种类* @return*/File toTargetType(File sourceFile, String basePath, String sourceFileName, JodConverterSupportOutputType type);
发送文件流
public void sendFileStream(HttpServletResponse response,InputStream fileInputStream){// 发送文件流try {@Cleanup OutputStream fileOutputStream = response.getOutputStream();// 把输入流copy到输出流IOUtils.copy(fileInputStream, fileOutputStream);fileOutputStream.flush();} catch (IOException e) {log.error("文件流发送失败,IO出错",e);throw ProblemSolver.server(ProblemCode.FILE_PREVIEW_IO_ERROR).build();}}
清空文件夹
public static boolean emptyFolder(String path) {File file = new File(path);if (!file.exists()) {//判断是否待删除目录是否存在log.error("文件或者目录不存在");return false;}String[] content = file.list();//取得当前目录下所有文件和文件夹for (String name : content) {File temp = new File(path, name);if (temp.isDirectory()) {//判断是否是目录emptyFolder(temp.getAbsolutePath());//递归调用,删除目录里的内容temp.delete();//删除空目录} else {if (!temp.delete()) {//直接删除文件log.error("文件:{} 删除失败" , name);}}}return true;}
public static boolean isImage(File file,String contentType) {if (StringUtils.isEmpty(contentType))return false;else if (ImgContentTypeEnum.isImage(contentType))return true;else {try {BufferedImage bi = ImageIO.read(file);if(bi == null){return false;}else {return true;}} catch (Exception e) {log.error("判断当前文件是否是图片类型异常", e);return false;}}}
public enum ImgContentTypeEnum {APPLICATIONJPG("application/x-jpg","jpg"),APPLICATIONIMG("application/x-img","img"),APPLICATIONPNG("application/x-png","png"),APPLICATIONBMP("application/x-bmp","bmp"),APPLICATIONTIF("application/x-tif","tif"),APPLICATIONPCX("application/x-pcx","pcx"),APPLICATIONTGA("application/x-tga","tga"),IMAGEJPG("image/jpeg","jpg"),IMAGEPNG("image/png","png"),IMAGETIF("image/tiff","tif"),IMAGEGIF("image/gif","gif"),IMAGEWBMP("image/vnd.wap.wbmp","wbmp"),;private String code;private String value;ImgContentTypeEnum(String code,String value){this.code = code;this.value = value;}public static boolean isImage(String contentType){for (ImgContentTypeEnum e: ImgContentTypeEnum.values()){if (contentType.toLowerCase().equals(e.code.toLowerCase())){return true;}}return false;}
}
public File imgFilePixelTransition(FileInformation fileInformation, String size) {if (StringUtils.isEmpty(size)){return this.getImgFile(fileInformation);}else{try {String[] sizes = size.toLowerCase().split("x");int width = Integer.parseInt(sizes[0]);int height = Integer.parseInt(sizes[1]);// 查询是否已经存在对应像素图片文件StringBuffer stringBuffer = new StringBuffer();stringBuffer.append(fileUploadConfig.getBasePath()).append(File.separator).append(FileConstants.THUMBNAIL).append(File.separator).append(fileInformation.getPath()).append("_").append(width).append("x").append(height);String destinationFilePath = stringBuffer.toString();File destinationFile = new File(destinationFilePath);if (destinationFile.exists())return destinationFile;// 不存在对应像素图片,新建像素图片// 获取用于低质量图片或者原图File sourceImgFile = this.getImgFile(fileInformation);// 检查size比例是否符合要求if (!checkImgZoomOutSize(sourceImgFile,width,height)){throw ProblemSolver.client(ProblemCode.FILE_PREVIEW_IMG_SIZE_NOT_LEGAL).build();}// 获取文件的绝对路径if (!fileUploadConfig.getBasePath().endsWith(File.separator)) {fileUploadConfig.setBasePath(fileUploadConfig.getBasePath() + File.separator);}// 创建图片临时目录if (!destinationFile.getParentFile().exists()) {logger.debug("创建目录{}", destinationFile.getParentFile().getPath());destinationFile.getParentFile().mkdirs();}@Cleanup OutputStream os = new FileOutputStream(destinationFilePath);//按指定大小把图片进行缩放(会遵循原图高宽比例)Thumbnails.of(sourceImgFile).size(width, height).toOutputStream(os);//变为width*height,遵循原图比例缩或放到width*某个高度return new File(destinationFilePath);} catch (NumberFormatException e) {logger.error("图片像素转换参数size:{}有误,无法识别",size,e);throw ProblemSolver.client(ProblemCode.FILE_PREVIEW_IMG_SIZE_WRONG).build();} catch (FileNotFoundException e) {logger.error("文件不存在",e);throw ProblemSolver.server(ProblemCode.FILE_NOT_FOUND).build();} catch (IOException e) {logger.error("IO出错",e);throw ProblemSolver.server(ProblemCode.FILE_PREVIEW_IO_ERROR).build();}}}
/*** 获取图片文件,优先取低质量图* @param fileInformation* @return*/@Overridepublic File getImgFile(FileInformation fileInformation){String fileBasePath = fileUploadConfig.getBasePath();StringBuffer stringBuffer = new StringBuffer();String lowImgFilePath = stringBuffer.append(fileBasePath).append(File.separator).append(FileConstants.LOW_QUALITY).append(File.separator).append(fileInformation.getPath()).toString();File file = new File(lowImgFilePath);if (!file.exists()){// 获取原图file = this.getFile(fileInformation);}return file;}
public class FileConstants {/*** 图片宽度默认缩放比例*/public static final int DEFAULT_SCALE = 1;/*** 图片达到缩放的范围*/public static final int IMAGE_SCALING_RANGE= 1000;/*** 图片大小压缩比例*/public static final double OUTPUTQUALITY = 0.2f;/*** 文件是否删除* 0: 否* 1:是*/public static final String FILE_NOT_DELETE= "0";public static final String FILE_IS_DELETE = "1";/*** 图片存放路径*/public static final String LOW_QUALITY = "low-quality";public static final String THUMBNAIL = "thumbnail";
}
/*** 检查图片缩小的长宽是否符合约定* @param img* @param width* @param height* @return* @throws IOException*/private boolean checkImgZoomOutSize(File img,int width,int height) throws IOException {BufferedImage buff = ImageIO.read(new FileInputStream(img));//得到图片的宽度int imgWidth = buff.getWidth();//得到图片的高度int imgHeight = buff.getHeight();return width <= imgWidth && height <= imgHeight && width > 0 && height > 0;}
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//import java.net.URI;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.zalando.problem.Problem;
import org.zalando.problem.ProblemBuilder;
import org.zalando.problem.Status;public class ProblemSolver {private static final Logger log = LoggerFactory.getLogger(ProblemSolver.class);public static final String KEY_TIMESTAMP = "timestamp";public ProblemSolver() {}public static ProblemBuilder client(ProblemCodeDefinition problemCodeDefinition) {URI instanceUri = null;String detail = problemCodeDefinition.getDetail();Long logNo = System.currentTimeMillis();try {instanceUri = URI.create(((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest().getRequestURI());detail.concat(String.format("【日志定位标识:%d】", logNo));} catch (Exception var5) {}log.error("异常编号:{},异常概要:{}", logNo, problemCodeDefinition.getDetail());return Problem.builder().withStatus(Status.BAD_REQUEST).withTitle(problemCodeDefinition.getTitle()).withDetail(problemCodeDefinition.getDetail()).withType(problemCodeDefinition.getTypeFormat() == null ? null : URI.create(String.format(problemCodeDefinition.getTypeFormat(), problemCodeDefinition.getTitle()))).with("timestamp", DateUtil.getCurrentTime()).withInstance(instanceUri);}public static ProblemBuilder server(ProblemCodeDefinition problemCodeDefinition) {URI instanceUri = null;String detail = problemCodeDefinition.getDetail();Long logNo = System.currentTimeMillis();try {instanceUri = URI.create(((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest().getRequestURI());detail = detail.concat(String.format("【日志定位标识:%d】", logNo));} catch (Exception var5) {}log.error("异常编号:{}", logNo);return Problem.builder().withStatus(Status.INTERNAL_SERVER_ERROR).withTitle(problemCodeDefinition.getTitle()).withDetail(detail).withType(problemCodeDefinition.getTypeFormat() == null ? null : URI.create(String.format(problemCodeDefinition.getTypeFormat(), problemCodeDefinition.getTitle()))).with("timestamp", DateUtil.getCurrentTime()).withInstance(instanceUri);}
}
好了 java之-文件预览终极解决方案 学习结束了 友友们 点点关注不迷路 老铁们!!!!!