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);
异常解决
注意是中文转化乱码的问题
解决思路一:安装中文包
//搜索libreoffice的中文包,如果有,安装即可
yum search libreoffice
//搜索openoffice的中文包,如果有,安装即可
yum search openoffice
//搜索unoconv的中文版,如果有,安装即可
yum search unoconv
举例: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;
}
}
附件上传效果
预览效果
Tips:因为Office文档在上传完毕时,就已经转换为PDF,PDF文件的URL可以直接通过Iframe配在src进行预览
注意:此处代码是上传文档后,就是实时同步执行转换PDF操作,但是如果文档过大,可以改为异步执行哈,不然上传的时候一直卡着,小于5M的文档可以,同步执行,转换过程大概就几秒钟,影响不大。
上一篇: 微信又上“骚”操作!!!