欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Office文档上传后实时转换为PDF格式_图片文件上传后实时裁剪_实现在线预览Office文档

程序员文章站 2024-01-15 15:26:46
...

Office文档上传后实时转换为PDF格式_图片文件上传后实时裁剪

 

前置条件

  • 安装LibreOffice
  • 安装OpenOffice
  • 安装Unoconv
  • 安装ImageMagick.x86_64
  • 安装GraphicsMagick.x86_64

 

思路说明

office文档上传后,执行Shell脚本命令,转换文档

libreoffice命令:

//如果是Word文档,则转化为PDF ,如果是Excel,则转换为html(将pdf:writer_pdf_Export替换为html) ,{src}替换为待转换文档全路径+名称,{des}替换为转换后存放路径
command = "libreoffice --convert-to pdf:writer_pdf_Export {src} --outdir {des}";

openoffice命令:

//如果是Word文档,则转化为PDF ,如果是Excel,则转换为html(将pdf:writer_pdf_Export替换为html) ,{src}替换为待转换文档全路径+名称,{des}替换为转换后存放路径
command = "soffice --headless --invisible --convert-to pdf:writer_pdf_Export {src} --outdir {des} "

unoconv命令:

//老版本的Word可能转换异常,使用unoconv转换;{src}替换为待转换文档全路径+名称,{des}替换为转换后存放路径
command = "unoconv -f pdf {src} -o {des} ";

图片文档上传后,执行Shell脚本命令,压缩或裁剪图片

//裁剪图片目录,注意{src}原图片路径+命令 {des}目标图片路径+命令
command = "convert {src} -resize 240x160 {des} "

执行命令如下:

//Java执行操作系统Shell命令
Runtime.getRuntime().exec(command);

Office文档上传后实时转换为PDF格式_图片文件上传后实时裁剪_实现在线预览Office文档

 

异常解决

注意是中文转化乱码的问题

解决思路一:安装中文包

//搜索libreoffice的中文包,如果有,安装即可
yum search libreoffice

//搜索openoffice的中文包,如果有,安装即可
yum search openoffice

//搜索unoconv的中文版,如果有,安装即可
yum search unoconv

Office文档上传后实时转换为PDF格式_图片文件上传后实时裁剪_实现在线预览Office文档

Office文档上传后实时转换为PDF格式_图片文件上传后实时裁剪_实现在线预览Office文档

举例:libreoffice的中文包,简体、繁体一并安装了,免得有些文档有繁体,转换后乱码

libreoffice-langpack-zh-Hans.x86_64 : Simplified Chinese language pack for LibreOffice
libreoffice-langpack-zh-Hant.x86_64 : Traditional Chinese language pack for LibreOffice

解决思路二:复制Windows上的字体包到Linux系统上并安装

具体方法:https://blog.csdn.net/Aria_Miazzy/article/details/103830850

 

转换代码

package org.jeecg.common.system.controller;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.jeecg.common.api.vo.Result;
import org.jeecg.common.util.BashUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.ModelAndView;

import lombok.extern.slf4j.Slf4j;

/**
 * <p>
 * 用户表 前端控制器
 * </p>
 *
 * @Author scott
 * @since 2018-12-20
 */
@Slf4j
@RestController
@RequestMapping("/sys/common")
public class CommonController {

	@Value(value = "${jeecg.path.upload}")
	private String uploadpath = "/root/jeecg/upFiles";

	@Value(value = "${jeecg.path.convert}")
	private String convert = "convert";

	/**
	 * @Author 政辉
	 * @return
	 */
	@GetMapping("/403")
	public Result<?> noauth()  {
		return Result.error("没有权限,请联系管理员授权");
	}

	/**
	 * @function 上传函数
	 * @param request
	 * @param response
	 * @return
	 */
	@PostMapping(value = "/upload")
	public Result<?> upload(HttpServletRequest request, HttpServletResponse response) {

		//定义返回结果
		Result<?> result = new Result<>();

		//定义上传区域块
		try {

			//获取上传目录
			String ctxPath = uploadpath;
			//定义文件名称
			String fileName = null;
			//定义图片名称
			String thumborName = null;
            //设置图片名称
            String thumborName100x60 =null;
            //定义图片名称
            String originName = null;
            //定义上传文件子目录
			String bizPath = "files";
			//获取当前时间
			String nowtime = new SimpleDateFormat("yyyyMMddhhmmssSSS").format(new Date());
			//获取文件上传目录
			File file = new File(ctxPath + File.separator + bizPath);

			//如果文件不存在,则创建文件根目录
			if (!file.exists()) {
				file.mkdirs();
			}

			//获取多媒体Request请求对象
			MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;

			// 获取上传文件对象
			MultipartFile mf = multipartRequest.getFile("file");

			//获取文件名
			String orgName = mf.getOriginalFilename();
			//获取文件类型
			String fileType = orgName.substring(orgName.indexOf(".")).toLowerCase();

			//重命名文件
			fileName = nowtime + "_" + orgName.substring(0, orgName.lastIndexOf(".")).replaceAll(" ","")  + fileType;

			//设置图片名称
			thumborName = nowtime  + "_" + orgName.substring(0, orgName.lastIndexOf(".")).replaceAll(" ","") + "_S240x160" + fileType;

            //设置图片名称
            thumborName100x60 = nowtime  + "_" + orgName.substring(0, orgName.lastIndexOf(".")).replaceAll(" ","") + "_S100x60" + fileType;

            //设置图片名称
            originName = nowtime  + "_" + orgName.substring(0, orgName.lastIndexOf(".")).replaceAll(" ","") + fileType;

			//设置保存路径
			String savePath = file.getPath() + File.separator + fileName;

			//设置可以执行保存的文件对象
			File savefile = new File(savePath);

			//执行保存文件操作
			FileCopyUtils.copy(mf.getBytes(), savefile);

			//设置应显示的文件保存路径
			String dbpath = bizPath + File.separator + fileName;

			//字符串\\转换为/
			if (dbpath.contains("\\")) {
				dbpath = dbpath.replace("\\", "/");
			}

			//定义待执行命令
			String command = null;

			//如果是Excel文档,则转化为Html,如果是Word文档,则转化为PDF文档,如果是PPT文档,则转化为PDF文档,如果是图片,则进行压缩处理
			if(fileType.equals(".xlsx") || fileType.equals(".xls")) {
				//如果是Excel文档,则转化为Html
				command = "libreoffice --convert-to html {src} --outdir {des}";
			} else if(fileType.equals(".doc")) {
				//老版本的Word可能转换异常,使用unoconv转换
				command = "unoconv -f pdf {src} -o {des} ";
			} else if(fileType.equals(".ppt")) {
				//老版本的Word可能转换异常,使用unoconv转换
				command = "unoconv -f pdf {src} -o {des} ";
			} else if(fileType.equals(".docx")){
			    //如果是Word文档,则转化为PDF
				command = "libreoffice --convert-to pdf:writer_pdf_Export {src} --outdir {des}";
			} else if(fileType.equals(".pptx")){
			    //如果是PPT文档,则转化为PDF
				command = "libreoffice --convert-to pdf:writer_pdf_Export {src} --outdir {des}";
			} else if(fileType.equals(".jpeg") || fileType.equals(".jpg") || fileType.equals(".gif") || fileType.equals(".png") || fileType.equals(".bmp")){
				//定义图片压缩脚本 规格240x160 //command = "convert -strip -interlace Plane -gaussian-blur 0.02 -quality 85% {src} {src}";
				command = "convert {src} -resize 240x160 {des} "
						.replace("{src}",ctxPath + File.separator + bizPath + File.separator + fileName)
						.replace("{des}", ctxPath + File.separator + bizPath + File.separator + "images" + File.separator + thumborName);
				//执行图片压缩命令
				BashUtil.exec(command);

				//定义图片压缩脚本 规格100x60
				command = "convert {src} -resize 100x60 {des} "
						.replace("{src}",ctxPath + File.separator + bizPath + File.separator + fileName)
						.replace("{des}", ctxPath + File.separator + bizPath + File.separator + "images" + File.separator + thumborName100x60);
				//执行图片压缩命令
				BashUtil.exec(command);

				//定义图片压缩脚本 规格1024x768
				command = "convert {src} -resize 1024x768 {des} "
						.replace("{src}",ctxPath + File.separator + bizPath + File.separator + fileName)
						.replace("{des}", ctxPath + File.separator + bizPath + File.separator + "origin" + File.separator + originName);
				//执行图片压缩命令
				BashUtil.exec(command);

				//执行图片裁剪脚本
				BashUtil.exec("bash /root/jeecg/upFiles/files/thumbor.sh");
			} else {
				command = "";
			}

			//执行shell命令区域
			try{
				//设置命令中的src des
				command = command.replace("{src}",ctxPath + File.separator + bizPath + File.separator + fileName);
				command = command.replace("{des}", ctxPath + File.separator + bizPath + File.separator + convert + File.separator);

				//打印日志
				log.info("command :" + command + " fileType:" + fileType + " ctxPath:" + ctxPath + " bizPath:" + bizPath + " fileName:" + fileName + " convert:" + convert) ;

				//先设置文档可读
				BashUtil.exec("chmod 755 -R " + ctxPath + File.separator + bizPath + File.separator + "*");

				//执行文档转换命令
				BashUtil.exec(command);

                //执行Git Push命令,将本次变动实时同步到远程Git仓库中
                BashUtil.exec("bash /root/jeecg/upFiles/files/start.sh");

			} catch (Exception e){
				log.error(e.getMessage(), e);
			}

			//设置返回消息
			result.setMessage(dbpath);

			//设置返回状态
			result.setSuccess(true);

		} catch (IOException e) {

			result.setSuccess(false);
			result.setMessage("保存文件异常");
			log.error(e.getMessage(), e);

		}

		//返回结果
		return result;

	}

	/**
	 * 预览图片
	 * 请求地址:http://localhost:8080/common/view/{user/20190119/e1fe9925bc315c60addea1b98eb1cb1349547719_1547866868179.jpg}
	 * 
	 * @param request
	 * @param response
	 */
	@GetMapping(value = "/view/**")
	public void view(HttpServletRequest request, HttpServletResponse response) {
		// ISO-8859-1 ==> UTF-8 进行编码转换
		String imgPath = extractPathFromPattern(request);
		// 其余处理略
		InputStream inputStream = null;
		OutputStream outputStream = null;
		try {
			imgPath = imgPath.replace("..", "");
			if (imgPath.endsWith(",")) {
				imgPath = imgPath.substring(0, imgPath.length() - 1);
			}
			response.setContentType("image/jpeg;charset=utf-8");
			String localPath = uploadpath;
			String imgurl = localPath + File.separator + imgPath;
			inputStream = new BufferedInputStream(new FileInputStream(imgurl));
			outputStream = response.getOutputStream();
			byte[] buf = new byte[1024];
			int len;
			while ((len = inputStream.read(buf)) > 0) {
				outputStream.write(buf, 0, len);
			}
			response.flushBuffer();
		} catch (IOException e) {
			log.error("预览图片失败" + e.getMessage());
			// e.printStackTrace();
		} finally {
			if (inputStream != null) {
				try {
					inputStream.close();
				} catch (IOException e) {
					log.error(e.getMessage(), e);
				}
			}
			if (outputStream != null) {
				try {
					outputStream.close();
				} catch (IOException e) {
					log.error(e.getMessage(), e);
				}
			}
		}

	}
	
	/**
	 * 下载文件
	 * 请求地址:http://localhost:8080/common/download/{user/20190119/e1fe9925bc315c60addea1b98eb1cb1349547719_1547866868179.jpg}
	 * 
	 * @param request
	 * @param response
	 * @throws Exception 
	 */
	@GetMapping(value = "/download/**")
	public void download(HttpServletRequest request, HttpServletResponse response) throws Exception {
		// ISO-8859-1 ==> UTF-8 进行编码转换
		String filePath = extractPathFromPattern(request);
		// 其余处理略
		InputStream inputStream = null;
		OutputStream outputStream = null;
		try {
			filePath = filePath.replace("..", "");
			if (filePath.endsWith(",")) {
				filePath = filePath.substring(0, filePath.length() - 1);
			}
			String localPath = uploadpath;
			String downloadFilePath = localPath + File.separator + filePath;
			File file = new File(downloadFilePath);
	         if (file.exists()) {
	        	 response.setContentType("application/force-download");// 设置强制下载不打开            
	 			response.addHeader("Content-Disposition", "attachment;fileName=" + new String(file.getName().getBytes("UTF-8"),"iso-8859-1"));
	 			inputStream = new BufferedInputStream(new FileInputStream(file));
	 			outputStream = response.getOutputStream();
	 			byte[] buf = new byte[1024];
	 			int len;
	 			while ((len = inputStream.read(buf)) > 0) {
	 				outputStream.write(buf, 0, len);
	 			}
	 			response.flushBuffer();
	         }
			
		} catch (Exception e) {
			log.info("文件下载失败" + e.getMessage());
			// e.printStackTrace();
		} finally {
			if (inputStream != null) {
				try {
					inputStream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (outputStream != null) {
				try {
					outputStream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

	}
	

	/**
	  *  把指定URL后的字符串全部截断当成参数 
	  *  这么做是为了防止URL中包含中文或者特殊字符(/等)时,匹配不了的问题
	 * @param request
	 * @return
	 */
	private static String extractPathFromPattern(final HttpServletRequest request) {
		String path = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
		String bestMatchPattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
		return new AntPathMatcher().extractPathWithinPattern(bestMatchPattern, path);
	}

}
package org.jeecg.common.util;

import io.netty.util.internal.StringUtil;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.io.InputStream;

/**
 * Bash命令行执行器
 * A001
 * A001A002
 * @Author zhangdaihao
 *
 */
@Slf4j
public class BashUtil {

	/**
	 * @function 执行Shell脚本命令
	 * @param command
	 * @return
	 */
	public static boolean exec(String command) {

		//如果传入参数为空,则直接返回
		if(command.equals("") || command == null){
			return false;
		}

		//执行状态
		int exitStatus = 0;

		// Process可以控制该子进程的执行或获取该子进程的信息
		Process process;

		try {
			log.info("exec cmd : " + command);
			process = Runtime.getRuntime().exec(command);// exec()方法指示Java虚拟机创建一个子进程执行指定的可执行程序,并返回与该子进程对应的Process对象实例。
			// 下面两个可以获取输入输出流
			InputStream errorStream = process.getErrorStream();
			InputStream inputStream = process.getInputStream();
		} catch (IOException e) {
			log.error(" exec cmd error :" + command, e);
			return false;
		}

		try {
			exitStatus = process.waitFor();// 等待子进程完成再往下执行,返回值是子线程执行完毕的返回值,返回0表示正常结束
			// 第二种接受返回值的方法
			int i = process.exitValue(); // 接收执行完毕的返回值
			log.debug("i----" + i);
		} catch (InterruptedException e) {
			log.error("InterruptedException  exec {}", command, e);
			return false;
		}

		if (exitStatus != 0) {
			log.error("exec cmd exitStatus {}", exitStatus);
		} else {
			log.debug("exec cmd exitStatus {}", exitStatus);
		}

		// 销毁子进程
		process.destroy();
		// 子进程设置为空
		process = null;

		//返回执行结果
		return true;
	}

}

 

 

附件上传效果

Office文档上传后实时转换为PDF格式_图片文件上传后实时裁剪_实现在线预览Office文档

 

预览效果

Office文档上传后实时转换为PDF格式_图片文件上传后实时裁剪_实现在线预览Office文档

Office文档上传后实时转换为PDF格式_图片文件上传后实时裁剪_实现在线预览Office文档

Office文档上传后实时转换为PDF格式_图片文件上传后实时裁剪_实现在线预览Office文档

 

Tips:因为Office文档在上传完毕时,就已经转换为PDF,PDF文件的URL可以直接通过Iframe配在src进行预览

 

注意此处代码是上传文档后,就是实时同步执行转换PDF操作,但是如果文档过大,可以改为异步执行哈,不然上传的时候一直卡着,小于5M的文档可以,同步执行,转换过程大概就几秒钟,影响不大。

相关标签: Office