package com.product.file.service;
|
|
import cn.hutool.core.collection.CollectionUtil;
|
import cn.hutool.core.io.FileUtil;
|
import cn.hutool.core.io.IoUtil;
|
import cn.hutool.core.util.IdUtil;
|
import com.product.common.lang.StringUtils;
|
import com.product.core.cache.util.RedisUtil;
|
import com.product.core.config.Global;
|
import com.product.core.entity.DataTableEntity;
|
import com.product.core.entity.FieldSetEntity;
|
import com.product.core.exception.BaseException;
|
import com.product.core.service.support.AbstractBaseService;
|
import com.product.core.spring.context.SpringMVCContextHolder;
|
import com.product.file.config.CmnConst;
|
import com.product.file.config.FileCode;
|
import com.product.file.util.FileUtils;
|
import com.product.module.sys.entity.SystemUser;
|
import com.product.module.sys.service.idel.IOnlineDocumentEditingService;
|
import com.product.util.BaseUtil;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.context.annotation.Primary;
|
import org.springframework.stereotype.Service;
|
import redis.clients.jedis.Jedis;
|
|
import javax.servlet.http.HttpServletResponse;
|
import java.io.File;
|
import java.io.IOException;
|
import java.nio.charset.StandardCharsets;
|
import java.util.*;
|
import java.util.stream.Collectors;
|
|
/**
|
* @Author cheng
|
* @Date 2022/4/11 10:08
|
* @Desc 文档在线编辑业务类
|
*/
|
@Service
|
@Primary
|
public class OnlineDocumentEditService extends AbstractBaseService implements IOnlineDocumentEditingService {
|
/**
|
* 文档编辑标识key
|
*/
|
private final String DOCUMENT_EDIT_KEY = "document-edit:";
|
|
@Autowired
|
FileManagerService fileManagerService;
|
|
@Autowired
|
FileUtils fileUtils;
|
|
/**
|
* 文档套红
|
*
|
* @param ff
|
* @param file
|
*/
|
public void nestRedDocument(FieldSetEntity ff, File file) {
|
try {
|
String document_template = ff.getString("document_template");
|
String document_template_tail = ff.getString("document_template_tail");
|
String fileUuid = ff.getString("file_uuid");
|
FieldSetEntity fieldSetEntity = getBaseDao().getFieldSetEntity(CmnConst.PRODUCT_SYS_ATTACHMENTS, fileUuid, false);
|
//获取文件类型
|
String fileName = fieldSetEntity.getString(CmnConst.FILE_NAME);
|
//判断是否为doc文件
|
String fileType = fileName.substring(fileName.lastIndexOf(".") + 1);
|
if ("doc".equals(fileType)) {
|
//将doc文件转换为docx文件
|
File f = file;
|
file = com.product.file.util.FileUtil.toDocx(file);
|
if (f != null) {
|
f.delete();
|
}
|
}
|
List<File> fileList = new ArrayList<>(3);
|
if (!StringUtils.isEmpty(document_template)) {
|
File file1 = fileManagerService.getFile(document_template);
|
//判断file1的文件类型
|
if (file1.getName().substring(file1.getName().lastIndexOf(".") + 1).equals("doc")) {
|
//转换为docx
|
File docx = com.product.file.util.FileUtil.toDocx(file1);
|
FileUtil.del(file1);
|
file1 = docx;
|
}
|
fileList.add(file1);
|
fileList.add(file);
|
} else {
|
fileList.add(file);
|
}
|
if (!StringUtils.isEmpty(document_template_tail)) {
|
fileList.add(fileManagerService.getFile(document_template_tail));
|
}
|
File mergeFile = MergeDoc.mergeDoc(fileList, Global.getSystemConfig("upload.file.temp.path", "./attachment/temp") + File.separator + "nest_red_document_" + IdUtil.randomUUID() + "_" + ff.getString("file_uuid"));
|
if (mergeFile != null && mergeFile.isFile()) {
|
if ("doc".equals(fileType)) {
|
//将docx文件转换为doc文件
|
File f = mergeFile;
|
mergeFile = com.product.file.util.FileUtil.toDoc(f);
|
if (f != null) {
|
f.delete();
|
}
|
}
|
HashMap<String, File> objectObjectHashMap = new HashMap<>();
|
objectObjectHashMap.put("mergeFile", mergeFile);
|
uploadFile(ff.getString("file_uuid"), objectObjectHashMap);
|
} else {
|
throw new BaseException(FileCode.NEST_RED_DOCUMENT_FAIL);
|
}
|
fileList.forEach(FileUtil::del);
|
} catch (BaseException e) {
|
throw e;
|
} catch (Exception e) {
|
e.printStackTrace();
|
throw new BaseException(FileCode.NEST_RED_DOCUMENT_FAIL);
|
}
|
}
|
|
|
/**
|
* 在线预览或编辑获取文件
|
*
|
* @param response
|
* @param uuid
|
* @throws IOException
|
*/
|
public void getFile(HttpServletResponse response, String uuid) throws IOException {
|
String currentUserId = SpringMVCContextHolder.getCurrentUserId();
|
if (StringUtils.isEmpty(currentUserId)) {
|
return;
|
}
|
String redisKey = this.DOCUMENT_EDIT_KEY + uuid + "-" + currentUserId;
|
//在redis中获取缓存 根据缓存是否存在判断该文件是否标识为正在编辑的状态
|
Map<String, Object> map = (Map<String, Object>) RedisUtil.get(redisKey); //查询文件记录
|
FieldSetEntity fse = getBaseDao().getFieldSetEntity(CmnConst.PRODUCT_SYS_ATTACHMENTS, uuid, false);
|
if (FieldSetEntity.isEmpty(fse)) {
|
throw new BaseException(FileCode.GET_FILE_RECORD_FAIL);
|
}
|
if (map != null) {
|
//正在编辑 准备输出已编辑过但未提交的文件
|
String dir = fse.getString(CmnConst.ATTACHMENT_URL);
|
String fileName = fse.getString(CmnConst.ATTACHMENT_TITLE);
|
//已编辑未提交的文件路径
|
try {
|
File sourceFile = fileUtils.getFile(fse.getBoolean(CmnConst.UPLOAD_SIGN), dir, fileName + "_" + currentUserId + "_" + map.get("uniqueKey"), fse.getBoolean(CmnConst.ENCRPT_SIGN));
|
if (sourceFile != null && sourceFile.isFile()) {
|
//输出
|
IoUtil.write(response.getOutputStream(), true, FileUtil.readBytes(sourceFile));
|
sourceFile.delete();
|
return;
|
}
|
} catch (BaseException e) {
|
//捕获异常
|
}
|
}
|
IoUtil.write(response.getOutputStream(), true, fileManagerService.getFileContent(fse));
|
}
|
|
/**
|
* 清空正在编辑文档状态 根据用户
|
*
|
* @param userId 用户id
|
*/
|
public void clearBeingEditDocumentStatus(String userId) {
|
if (StringUtils.isEmpty(userId)) {
|
return;
|
}
|
//正则匹配redis中的key
|
Set<byte[]> keys = RedisUtil.keys(this.DOCUMENT_EDIT_KEY + "*-" + userId);
|
if (keys != null && keys.size() > 0) {
|
String[] strKeys = new String[keys.size()];
|
int i = 0;
|
for (byte[] key : keys) {
|
strKeys[i++] = new String(key);
|
}
|
//清空redis
|
RedisUtil.del(keys.toArray(new String[keys.size()]));
|
}
|
}
|
|
/**
|
* 业务数据保存时底层调用此方法
|
* 调用此方法后将文件标记为已保存 清除正在编辑的状态标识
|
*
|
* @param fileUuid 文件uuid
|
* @param userId 操作人id
|
* @return
|
*/
|
@Override
|
public boolean saveDocNotice(String fileUuid, int userId) throws BaseException {
|
|
if (StringUtils.isEmpty(fileUuid)) {
|
return false;
|
}
|
String[] fileUuids = fileUuid.split(",");
|
//查询文件记录
|
DataTableEntity dt = getBaseDao().listTable(CmnConst.PRODUCT_SYS_ATTACHMENTS, BaseUtil.buildQuestionMarkFilter("uuid", fileUuids, true));
|
if (!DataTableEntity.isEmpty(dt)) {
|
// throw new BaseException(FileCode.GET_FILE_RECORD_FAIL);
|
for (int i = 0; i < dt.getRows(); i++) {
|
FieldSetEntity fse = dt.getFieldSetEntity(i);
|
try {
|
String redisKey = this.DOCUMENT_EDIT_KEY + fse.getUUID() + "-" + userId;
|
if (!RedisUtil.exists(redisKey)) {
|
continue;
|
}
|
Map<String, Object> map = (Map<String, Object>) RedisUtil.get(redisKey);
|
if (map != null) {
|
String dir = fse.getString(CmnConst.ATTACHMENT_URL);
|
String fileName = fse.getString(CmnConst.ATTACHMENT_TITLE);
|
if (!fileUtils.fileIsExist(fse.getBoolean(CmnConst.UPLOAD_SIGN), dir, fileName)) {
|
continue;
|
}
|
//系统附件存放的根路径
|
File sourceFile = fileUtils.getFile(fse.getBoolean(CmnConst.UPLOAD_SIGN), dir, fileName + "_" + userId + "_" + map.get("uniqueKey"), fse.getBoolean(CmnConst.ENCRPT_SIGN));
|
if (sourceFile != null && sourceFile.isFile()) {
|
File targetFile = fileUtils.getFile(fse.getBoolean(CmnConst.UPLOAD_SIGN), dir, fileName, false);
|
if (targetFile != null && targetFile.isFile()) {
|
//备份源文件
|
fileUtils.uploadOtherFile(fse.getBoolean(CmnConst.ENCRPT_SIGN), dir, targetFile, fileName + "_back_" + userId + "_" + map.get("uniqueKey"));
|
targetFile.delete();
|
}
|
|
//将修改后的文件覆盖到源文件
|
fileUtils.replaceFile(dir, fileName, fse.getString(CmnConst.FILE_NAME), sourceFile, fse.getBoolean(CmnConst.ENCRPT_SIGN), fse.getBoolean(CmnConst.UPLOAD_SIGN), fse.getBoolean(CmnConst.VIEW_ONLINE_SIGN));
|
if (fse.getBoolean(CmnConst.ENCRPT_SIGN)) {
|
fileUtils.deleteFilesServerOnFile(dir, fileName + "_" + userId + "_" + map.get("uniqueKey"));
|
}
|
sourceFile.delete();
|
}
|
}
|
RedisUtil.del(redisKey);
|
} catch (Exception e) {
|
e.printStackTrace();
|
SpringMVCContextHolder.getSystemLogger().error(e);
|
// return false;
|
}
|
}
|
}
|
|
return true;
|
}
|
|
|
/**
|
* weboffice 保存文件(手动、自动)
|
*
|
* @param uuid 文件的uuid
|
* @param fileMap 新提交的文件
|
* @throws BaseException
|
*/
|
public void uploadFile(String uuid, Map<String, File> fileMap) throws BaseException {
|
//查询文件记录
|
FieldSetEntity fse = getBaseDao().getFieldSetEntity(CmnConst.PRODUCT_SYS_ATTACHMENTS, uuid, false);
|
if (FieldSetEntity.isEmpty(fse)) {
|
throw new BaseException(FileCode.GET_FILE_RECORD_FAIL);
|
}
|
String userId = SpringMVCContextHolder.getCurrentUserId();
|
if (StringUtils.isEmpty(userId)) {
|
return;
|
}
|
//获取源文件路径
|
String dir = fse.getString(CmnConst.ATTACHMENT_URL);
|
String fileName = fse.getString(CmnConst.ATTACHMENT_TITLE);
|
if (!fileUtils.fileIsExist(fse.getBoolean(CmnConst.UPLOAD_SIGN), dir, fileName)) {
|
throw new BaseException(FileCode.INVALID_FILE_PATH);
|
}
|
String redisKey = this.DOCUMENT_EDIT_KEY + uuid + "-" + userId;
|
Map<String, Object> map = (Map<String, Object>) RedisUtil.get(redisKey);
|
|
//系统附件存放的根路径
|
File file = fileMap.values().toArray(new File[]{})[0];
|
if (fse.getBoolean(CmnConst.ENCRPT_SIGN)) {
|
String filePath = Global.getSystemConfig("temp.dir", "") + "/onlineEdit_" + redisKey;
|
//加密文件
|
com.product.file.util.FileUtil.copyFile(file, filePath, 1);
|
file.delete();
|
file = new File(filePath);
|
}
|
FileUtils.uploadOtherFile(fse.getBoolean(CmnConst.ENCRPT_SIGN), dir, file, fileName + "_" + userId + "_" + map.get("uniqueKey"));
|
file.delete();
|
}
|
|
public void deleteFile(String dir, String fileName) {
|
SystemUser currentUser = SpringMVCContextHolder.getCurrentUser();
|
if (currentUser != null && !StringUtils.isEmpty(currentUser.getToken_info())) {
|
// TokenValidateInterceptor
|
}
|
}
|
|
/**
|
* 获取过期时间
|
*
|
* @return 过期时间 单位 秒
|
*/
|
private int getExpirationTime() {
|
int refreshTokenExpiration = Global.getPropertyToInteger("refresh.token.expiration", "8") * 60 * 60;
|
int tokenExpiration = Global.getPropertyToInteger("token.expiration", (8 * 60) + "") * 60;
|
|
return refreshTokenExpiration > tokenExpiration ? refreshTokenExpiration : tokenExpiration;
|
}
|
|
/**
|
* 标识文档正在编辑
|
*
|
* @param fileUuid
|
* @return
|
*/
|
public void signDocumentEdit(String fileUuid) throws BaseException {
|
String userId = SpringMVCContextHolder.getCurrentUserId();
|
if (StringUtils.isEmpty(userId)) {
|
throw new BaseException(FileCode.GET_FILE_RECORD_FAIL);
|
}
|
String key = this.DOCUMENT_EDIT_KEY + fileUuid + "-" + userId;
|
//模糊匹配key
|
Set<byte[]> keyBytes = RedisUtil.keys((this.DOCUMENT_EDIT_KEY + fileUuid + "-*").getBytes(StandardCharsets.UTF_8));
|
if (!CollectionUtil.isEmpty(keyBytes)) {
|
Set<String> keys = keyBytes.stream().map(item -> new String(item, StandardCharsets.UTF_8)).collect(Collectors.toSet());
|
boolean remove = keys.remove(this.DOCUMENT_EDIT_KEY + fileUuid + "-" + userId);
|
if (keys != null && keys.size() > 0) {
|
//正在被编辑
|
String existsKey = keys.toArray(new String[]{})[0];
|
//这里会抛出正在编辑的异常
|
throwBeingEditDocument(existsKey.substring(existsKey.lastIndexOf("-") + 1));
|
} else if (remove) {
|
RedisUtil.setOutTime(key, getExpirationTime());
|
return;
|
}
|
}
|
|
Map<String, Object> params = new HashMap<>();
|
params.put("userId", userId);
|
params.put("fileUuid", fileUuid);
|
params.put("uniqueKey", IdUtil.randomUUID());
|
RedisUtil.set(key, params);
|
RedisUtil.setOutTime(key, getExpirationTime());
|
}
|
|
/**
|
* 正在编辑文档错误抛出
|
*
|
* @param userId
|
* @throws BaseException
|
*/
|
private void throwBeingEditDocument(Object userId) throws BaseException {
|
FieldSetEntity userInfo = BaseUtil.getSingleInfoByCache("用户缓存", new String[]{String.valueOf(userId)});
|
String user_name;
|
if (userInfo != null && !StringUtils.isEmpty(userInfo.getString("user_name"))) {
|
user_name = userInfo.getString("user_name");
|
} else {
|
user_name = "未知用户";
|
}
|
throw new BaseException(FileCode.DOCUMENT_BEING_EDITED.getValue(), FileCode.DOCUMENT_BEING_EDITED.getText().replace("{{userName}}", user_name));
|
}
|
|
}
|