标签
文件
字数
26719 字
阅读时间
153 分钟
实现文件上传、下载、转换功能
相关依赖
groovy
//POI
compile group: 'org.apache.poi', name: 'poi', version: '4.1.0'
compile group: 'org.apache.poi', name: 'poi-ooxml', version: '4.1.0'
compile group: 'org.apache.poi', name: 'poi-ooxml-schemas', version: '4.1.0'
compile group: 'org.apache.poi', name: 'poi-scratchpad', version: '4.1.0'
compile 'cn.aghost:fastdfs-client-java:1.29.0'
compile 'ant:ant:1.7.0'
compile group: 'com.aspose', name: 'aspose-words', version: '15.8.0'
compile group: 'com.commnetsoft', name: 'aspose-pdf', version: '18.9'
compile group: 'org.apache.pdfbox', name: 'pdfbox', version: '2.0.18'
compile group: 'com.aliyun.oss',name: 'aliyun-sdk-oss', version: '3.10.2'
compile group: 'net.sourceforge.jexcelapi', name: 'jxl', version: '2.6.12'
//html转换PDF
implementation 'com.itextpdf:itext7-core:7.1.9'
implementation 'com.itextpdf:html2pdf:2.1.6'
//html转Docx
compile ('org.docx4j:docx4j:6.1.1'){
exclude group: 'org.slf4j', module: 'slf4j-log4j12'
}
compile 'org.docx4j:docx4j-JAXB-Internal:8.1.4'
compile 'org.docx4j:xhtmlrenderer:3.0.0'
compile 'org.docx4j:docx4j-ImportXHTML:8.0.3'上传下载
定义接口
java
import com.commnetsoft.commons.utils.FileUtils;
import com.commnetsoft.commons.utils.StringUtils;
import com.commnetsoft.commons.utils.UriUtil;
import com.commnetsoft.file.constant.FileSystemConstant;
import com.commnetsoft.file.model.FileChunk;
import com.commnetsoft.file.model.FileEntity;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
public interface IFileHandler {
/**
* 从路由中获取文件路径
* @param uri 路由
* @return java.lang.String
* @author wuzm
* @date 2020/7/13
*/
default String getPath(String uri) throws UnsupportedEncodingException {
if(StringUtils.isBlank(uri)){
return null;
}
URI newUri = URI.create(uri);
String path = newUri.getPath();
return URLDecoder.decode(path, StandardCharsets.UTF_8.name());
}
default String getFilename(String uri, FileEntity fileEntity) throws UnsupportedEncodingException {
if(StringUtils.isBlank(uri)){
return null;
}
String filename;
if(null != fileEntity){
filename = fileEntity.getName();
}else{
filename = UriUtil.getParam(uri, "filename");
if(StringUtils.isBlank(filename)){
return filename;
}else{
filename = URLDecoder.decode(filename, StandardCharsets.UTF_8.name());
}
}
return filename;
}
default String getFileContentType(FileEntity fileEntity,String fileName){
if(null != fileEntity){
if(StringUtils.isBlank(fileName)){
fileName = fileEntity.getName();
}
if(StringUtils.isNotBlank(fileEntity.getMimetype())){
return fileEntity.getMimetype();
}
}
if(StringUtils.isNotBlank(fileName)){
return FileUtils.getMimeType(fileName);
}
return "application/octet-stream";
}
default Boolean isChunkFile(FileEntity fileEntity, String url) {
if (null != fileEntity) {
return fileEntity.getChunk() == FileSystemConstant.TRUE_NUM ? true : false;
}
return StringUtils.contains(url, FileChunk.FILE_UPLOADID);
}
default String getChunkFileUploadid(FileEntity fileEntity, String url) {
if (null != fileEntity && StringUtils.isNotBlank(fileEntity.getUploadid())) {
return fileEntity.getUploadid();
}
if (StringUtils.contains(url, FileChunk.FILE_UPLOADID)) {
return StringUtils.substring(StringUtils.substringAfter(url, FileChunk.FILE_UPLOADID + "="), 0, 32);
}
return null;
}
}工具类
java
import org.apache.commons.lang3.ArrayUtils;
import java.io.*;
import java.net.FileNameMap;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
/**
* 文件工具类
* @author sunwen
* @since 2019/12/27
*/
public class FileUtils extends org.apache.commons.io.FileUtils {
/**
* 创建文件夹
* @author sunwen
* @since 2020/1/7
*/
public static File mkdirs(String path) throws IOException {
File file = new File(path);
if(file.isDirectory()){
return file;
}else if(file.mkdirs()){
return file;
}
throw new IOException();
}
/**
* 根据文件获取mimeType
* @author sunwen
* @since 2019/12/27
*/
public static String getMimeType(File file){
return getMimeType(file.getName());
}
/**
* 根据文件获取mimeType
* @author sunwen
* @since 2019/12/27
*/
public static String getMimeType(String fileName){
FileNameMap fileNameMap = URLConnection.getFileNameMap();
return fileNameMap.getContentTypeFor(fileName);
}
/**
* 获取文件后缀
* @param fileName 文件名
* @author wuzm
* @date 2020/7/1
*/
public static String getSuffix(String fileName){
if(StringUtils.isBlank(fileName)){
return null;
}
return StringUtils.substringAfterLast(fileName,".");
}
/**
* 拆分大文件
* @param inputStream
* @param size 拆分后每个小文件的大小(单位:MB)
* @param fileName 原文件名称(带后缀)
* @author lijx
* @date 2020/12/11
*/
public static List<File> splitFile(InputStream inputStream, int size, String fileName) throws IOException {
if (size == 0 || null == inputStream) {
return null;
}
//获取文件名和文件后缀
String suffix = "";
if (StringUtils.isNotBlank(fileName)) {
String[] split = StringUtils.split(fileName, ".");
if (ArrayUtils.isNotEmpty(split) && split.length == 2) {
fileName = split[0];
suffix = "." + split[1];
}
} else {
fileName = UUIDUtils.generate();
}
File tempDirPath = new File(System.getProperty("java.io.tmpdir"));
List<File> files = new ArrayList<>();
FileOutputStream fos = null;
byte[] buffer = new byte[1024 * 1024];
int length = 0;
int total = 0;//每次写入1MB,每个文件写入的次数
int index = 0;
try {
File newFile = new File(tempDirPath, fileName + "_" + index + suffix);
fos = new FileOutputStream(newFile);
while ((length = inputStream.read(buffer)) != -1) {//不能一次性读完,大文件会内存溢出
fos.write(buffer, 0, length);
total++;
if (total != size) {
continue;
}
index++;
total = 0;
files.add(newFile);
newFile = new File(tempDirPath, fileName + "_" + index + suffix);
fos = new FileOutputStream(newFile);
}
if (total != 0) {
files.add(newFile);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != fos) fos.close();
}
return files;
}
/**
* 拆分大文件
* @param file
* @param size 拆分后每个小文件的大小(单位:MB)
* @author lijx
* @date 2020/12/11
*/
public static List<File> splitFile(File file, int size) throws IOException {
if (null == file) {
return null;
}
FileInputStream fileInputStream = null;
List<File> files = null;
try {
fileInputStream = new FileInputStream(file);
files = splitFile(fileInputStream, size, file.getName());
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != fileInputStream) fileInputStream.close();
}
return files;
}
}java
import org.apache.commons.collections.CollectionUtils;
import java.util.Collection;
import java.util.List;
/**
* 字符串工具类
*/
public class StringUtils extends org.apache.commons.lang3.StringUtils {
public static String defaultString(Object obj, String defaultStr){
return obj == null ? defaultStr : obj.toString();
}
/**
* 判断字符是否是纯字母
* @author sunwen
* @since 2019/9/11
*/
public static boolean isLetter(final CharSequence cs){
if (isEmpty(cs)) {
return false;
}
final int sz = cs.length();
for (int i = 0; i < sz; i++) {
char c = cs.charAt(i);
if (!(c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z')){
return false;
}
}
return true;
}
/**
* 判断字符是否是纯字母+数字
* @author sunwen
* @since 2019/9/11
*/
public static boolean isLetternumeric(final CharSequence cs){
if (isEmpty(cs)) {
return false;
}
final int sz = cs.length();
for (int i = 0; i < sz; i++) {
char c = cs.charAt(i);
if (!(c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' || c >= '0' && c <= '9')){
return false;
}
}
return true;
}
/**
* 判断字符串是否一个hex数字
* @author sunwen
* @since 2019/8/7
*/
public static boolean isHexNumeric(final CharSequence cs) {
if (isEmpty(cs)) {
return false;
}
final int sz = cs.length();
for (int i = 0; i < sz; i++) {
char c = cs.charAt(i);
if (!Character.isDigit(c) && !(c >= 'A' && c <= 'F') && !(c >= 'a' && c <= 'f')) {
return false;
}
}
return true;
}
/**
* 判断字符串是否符合java标识符名称
* @author sunwen
* @since 2019/4/2
*/
public static boolean isJavaIdentifier(final CharSequence cs) {
if (isEmpty(cs)) {
return false;
}
final int sz = cs.length();
for (int i = 0; i < sz; i++) {
if (i == 0) {
if (!Character.isJavaIdentifierStart(cs.charAt(i))) {
return false;
}
} else {
if (!Character.isJavaIdentifierPart(cs.charAt(i))) {
return false;
}
}
}
return true;
}
public static boolean isJavaIdentifierPart(final CharSequence cs) {
if (isEmpty(cs)) {
return false;
}
final int sz = cs.length();
for (int i = 0; i < sz; i++) {
if (!Character.isJavaIdentifierPart(cs.charAt(i))) {
return false;
}
}
return true;
}
/**
* 判断字符串是否复合java包名
* @author sunwen
* @since 2019/6/11
*/
public static boolean isJavaPackage(final String cs) {
if (isEmpty(cs)) {
return false;
}
if (startsWith(cs, "\\.") || endsWith(cs, "\\.")) {
return false;
}
String[] parts = split(cs, "\\.");
for (String str : parts) {
if (!isJavaIdentifier(str)) {
return false;
}
}
return true;
}
/**
* 数字分割
* @author sunwen
* @since 2019/5/10
*/
public static Integer[] splitInt(String str, String separatorChars) {
String[] parts = split(str, separatorChars);
Integer[] ints = new Integer[parts.length];
for (int i = 0; i < parts.length; i++) {
ints[i] = Integer.parseInt(parts[i]);
}
return ints;
}
public static String byteToHex(byte[] bytes){
StringBuilder builder = new StringBuilder();
if (bytes == null || bytes.length <= 0) {
return null;
}
for (int i = 0; i < bytes.length; i++) {
int v = bytes[i] & 0xFF;
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
builder.append(0);
}
builder.append(hv);
}
return builder.toString();
}
/**
* 将集合用指定字符进行合并成字符串
* @param collection 集合
* @param separatorChars 指定字符
* @author wuzm
* @date 2020/5/17
*/
public static String castToString(Collection collection ,String separatorChars){
if(CollectionUtils.isEmpty(collection)){
return "";
}
StringBuilder stringBuilder = new StringBuilder();
for (Object collectEle : collection) {
if(stringBuilder.length() > 0){
stringBuilder.append(separatorChars);
}
stringBuilder.append(collectEle);
}
return stringBuilder.toString();
}
}java
import org.apache.http.client.utils.URIUtils;
import org.springframework.lang.Nullable;
import java.net.URI;
import java.util.Objects;
/**
* URI工具类
*
* @author Brack.zhu
* @date 2019/7/31
*/
public class UriUtil {
//FileChunk.FILE_UPLOADID=“uploadid”;
private UriUtil() {
}
/**
* 获取最后一个path<br/>
* http://127.0.0.1:8080/styles/font/fontawesome-webfont.woff?v=4.7.0<br/>
* 返回 fontawesome-webfont.woff
*
* @param uri
* @return 无返回null
*/
public static String lastPath(URI uri) {
String[] paths = getPaths(uri);
if (null != paths && paths.length > 0) {
return paths[paths.length - 1];
}
return null;
}
/**
* 获取URI path集合<br/>
* http://127.0.0.1:8080/styles/font/fontawesome-webfont.woff?v=4.7.0<br/>
* 返回 [styles,font,fontawesome-webfont.woff]
*
* @param uri
* @return 无返回null
*/
public static String[] getPaths(URI uri) {
Objects.requireNonNull(uri);
String path = uri.getPath();
if (StringUtils.isNotEmpty(path)) {
return path.split("/");
}
return null;
}
/**
* URI路径提取文件扩展名
* @param path 路径地址(如:"/products/index.html")
* @return 文件扩展名 (如:"html")
*/
@Nullable
public static String getFileExtension(String path) {
int end = path.indexOf('?');
int fragmentIndex = path.indexOf('#');
if (fragmentIndex != -1 && (end == -1 || fragmentIndex < end)) {
end = fragmentIndex;
}
if (end == -1) {
end = path.length();
}
int begin = path.lastIndexOf('/', end) + 1;
int paramIndex = path.indexOf(';', begin);
end = (paramIndex != -1 && paramIndex < end ? paramIndex : end);
int extIndex = path.lastIndexOf('.', end);
if (extIndex != -1 && extIndex > begin) {
return path.substring(extIndex + 1, end);
}
return null;
}
/**
* Get the query of an URI.
*
* @param uri a string regarded an URI
* @return the query string; <code>null</code> if empty or undefined
*/
public static String getQuery(String uri) {
if (uri == null || uri.length() == 0) { return null; }
// consider of net_path
int at = uri.indexOf("//");
int from = uri.indexOf(
"/",
at >= 0 ? (uri.lastIndexOf("/", at - 1) >= 0 ? 0 : at + 2) : 0
);
// the authority part of URI ignored
int to = uri.length();
// reuse the at and from variables to consider the query
at = uri.indexOf("?", from);
if (at >= 0) {
from = at + 1;
} else {
return null;
}
// check the fragment
if (uri.lastIndexOf("#") > from) {
to = uri.lastIndexOf("#");
}
// get the path and query.
return (from < 0 || from == to) ? null : uri.substring(from, to);
}
/**
* 获取路径中的指定参数值
* @author wuzm
* Date 2020/1/9 21:08
*/
public static String getParam(String uri,String paramName){
if(StringUtils.isBlank(paramName)){
return uri;
}
String params = getQuery(uri);
if(StringUtils.isBlank(params)){
return null;
}
String[] paramsArr = StringUtils.split(params,"&");
if(null == paramsArr && paramsArr.length == 0){
return null;
}
String prefix = paramName + "=";
for (String paramMap : paramsArr) {
if (!StringUtils.startsWith(paramMap, prefix)) {
continue;
}
return StringUtils.substringAfter(paramMap, prefix);
}
return null;
}
/**
* 截取掉路由后最后的斜杠
* @author wuzm
* Date 2020/3/31 14:18
*/
public static String subUriLastSlash(String uri){
if(StringUtils.isBlank(uri)){
return uri;
}
return StringUtils.endsWith(uri, "/") ? uri.substring(0,uri.length()-1) : uri;
}
}实体类
java
import tk.mybatis.mapper.annotation.LogicDelete;
import javax.persistence.*;
import java.util.Date;
/**
* @className: FileEntity
* @author: lijx
* @date: 2020/7/1 11:12
* @version: 1.0
*/
@Table(name = "file_entity")
public class FileEntity implements AclEntity<Integer> {
public transient static final Integer PREFIXTYPE_THIS = 1;//搜索本级
public transient static final Integer PREFIXTYPE_SUB = 2;//搜索下级
public transient static final Integer PREFIXTYPE_CONTAIN = 3;//搜索包含
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
//原文件id
private String sourcefileids;
//所属文件系统名称空间
private String namespace;
//所属文件空间主键
private Integer spaceid;
//上传唯一标识
private String uploadid;
//文件名称
private String name;
//文件类型
private String mimetype;
//文件前缀
private String prefix;
//文件后缀
private String suffix;
//文件大小
private Long size;
//文件路径
private String url;
//过期时间
private Date expiretime;
//是否分片
private Integer chunk;
//分片数量
private Integer totalchunk;
//是否完成
private Integer completed;
//文件md5加密值
private String encryptvalue;
//文件分片后md5值集合的md5结果
private String chunkencryptvalue;
//访问策略: 1.公开读写 2.公开读-私有写 3.私有读写 4.默认规则
private Integer accesstype;
//拥有者,可用于查询
private String owner;
@OrderBy
//排序号
private Integer orderby;
//下载次数
private Integer downloadnum;
//创建时间
private Date createtime;
//修改时间
private Date updatetime;
//删除标识
private Integer filedeleted;
@LogicDelete
private Boolean deleted;
}java
import com.commnetsoft.db.model.IdEntity;
import tk.mybatis.mapper.annotation.LogicDelete;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
/**
* 文件分片表
* @className: FileChunk
* @author: lijx
* @date: 2020/7/1 11:12
* @version: 1.0
*/
@Table(name = "file_chunk")
public class FileChunk implements IdEntity<Integer> {
public transient static final String FILE_UPLOADID = "uploadid";
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
//文件id
private Integer fileid;
//分片名称
private String name;
//文件路径
private String url;
//文件大小
private long size;
//分片序号
private Integer number;
//文件md5加密值
private String encryptvalue;
@LogicDelete
private Boolean deleted;
}java
/**
* 文件空间表
* @className: FileSpace
* @author: lijx
* @date: 2020/7/1 11:11
* @version: 1.0
*/
@Table(name = "file_space")
public class FileSpace implements AclEntity<Integer> {
public static transient final String SPACECODE_DEFAULT = "defaultspace";//默认空间的code
public static transient final String SPACECODE_TEMP = "tempspace";//临时空间的code
public static transient final String NAME_DEFAULT = "默认文件空间";//默认空间的name
public static transient final String NAME_TEMP = "临时文件空间";//临时空间的name
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
//文件空间名称
private String name;
//文件空间拼音
private String namepy;
//文件空间编码
private String spacecode;
//系统名称空间
private String namespace;
//文件生命周期
private Integer lifecycle;
//拥有者,可用于查询
private String owner;
@OrderBy
private Integer orderby;
private Date createtime;
//访问策略: 1.公开读写 2.公开读-私有写 3.私有读写 4.默认规则
private Integer accesstype;
@LogicDelete
private Boolean deleted;常量
java
public interface FileSystemConstant {
String FILE_NAMESPACE = "file";
String FILE_PUBLIC_SPACE = "publicspace";
/**
* 数字类型是否:0.否 1.是
*/
Integer FALSE_NUM = 0;
Integer TRUE_NUM = 1;
/**
* 是否
*/
Boolean FALSE = false;
Boolean TRUE = true;
/**
* 访问类型:1.公开读写 2.公开读-私有写 3.私有读写 4.默认规则
*/
Integer ACCESSTYPE_PUBLIC = 1;
Integer ACCESSTYPE_PUBLICREAD_PRIVATEWRITE = 2;
Integer ACCESSTYPE_PRIVATE = 3;
Integer ACCESSTYPE_DEFAULT = 4;
/**
* 有效期常量
*/
Integer LIFECYCLE_FOREVER = 0;
/**
* 授权对象类型:1.文件系统 2.文件控件 3.文件
*/
Integer ACLENTITYTYPE_SYSTEM = 1;
Integer ACLENTITYTYPE_SPACE = 2;
Integer ACLENTITYTYPE_FILE = 3;
/**
* 授权类型
* 1.读 对于文件空间或文件有读的权限
* 2.写 对于文件空间或文件有写的权限
* 4.列表 对于文件空间或文件有查询列表的权限
*/
Integer AUTHTYPE_READ = 1;//读
Integer AUTHTYPE_WRITE = 2;//写
Integer AUTHTYPE_LIST = 4;//列表
/**
* IP校验正则
*/
String IPS = "^((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})(\\.((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})){3}$";
}处理程序
java
import com.commnetsoft.file.model.FileEntity;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
/**
* 读取文件处理程序
*/
public interface IFileReadHandler extends IFileHandler{
/**
* 自定义url scheme
* @param
* @return java.lang.String
* @author wuzm
* @date 2020/7/8
*/
String fileUrlSchema();
/**
* 文件下载
*
* @param response 响应
* @param fileEntity 文件实体
* @return void
* @author lijx
* date 2020/7/7 9:54
*/
void download(HttpServletResponse response, String uri, FileEntity fileEntity) throws IOException;
/**
* 读取文件
* @param response 响应
* @param uri 文件路径
* @param fileEntity 文件实体
* @return void
* @author wuzm
* @date 2020/7/9
*/
void readFile(HttpServletResponse response, String uri, FileEntity fileEntity) throws IOException;
/**
* 读取文件
* @param fileEntity 文件实体对象
* @param uri 文件路径
* @return java.io.InputStream
* @author wuzm
* @date 2020/8/3
*/
InputStream readFile(String uri, FileEntity fileEntity) throws IOException;
}java
/**
* 写文件的处理程序
*/
public interface IFileWriteHandler extends IFileHandler{
/**
* 文件处理类类型
* @param
* @return java.lang.String
* @author wuzm
* @date 2020/7/1
*/
String fileLocation();
/**
* 保存文件
* @param file 文件
* @param fileSpace 文件空间
* @param fileEntity 文件实体
* @return uri 保存后文件的路径
* @author wuzm
* @date 2020/7/1
*/
Result<String> save(MultipartFile file, FileSpace fileSpace, FileEntity fileEntity);
/**
* 删除文件
* @param fileEntity 文件实体
* @return com.commnetsoft.commons.Result
* @author wuzm
* @date 2020/7/13
*/
Result delete(FileEntity fileEntity, List<FileChunk> fileChunks);
}fastdfs处理程序
java
import com.alibaba.fastjson.JSON;
import com.commnetsoft.commons.Result;
import com.commnetsoft.commons.utils.StringUtils;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.exception.MicroRuntimeException;
import com.commnetsoft.file.FileError;
import com.commnetsoft.file.model.FileChunk;
import com.commnetsoft.file.model.FileEntity;
import com.commnetsoft.file.model.FileSpace;
import com.commnetsoft.file.service.FileChunkService;
import com.commnetsoft.file.service.FileEntityService;
import com.commnetsoft.file.utils.FastDFSUtil;
import com.commnetsoft.file.utils.IFileReadHandler;
import com.commnetsoft.file.utils.IFileWriteHandler;
import org.apache.commons.collections.CollectionUtils;
import org.apache.http.HttpStatus;
import org.csource.common.MyException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* @ClassName FastDFSFileHandler
* @Author wuzm
* @Date 2020/6/30 19:21
* @Version 1.0
*/
@Component
@RefreshScope
public class FastDFSFileHandler implements IFileWriteHandler, IFileReadHandler {
//FastDFS跟踪服务器访问地址,多个地址用,隔开
@Value("#{fileConfig.fastdfsTrackerServerPath}")
private String fastdfsTrackerServerPath;
//nginx服务器访问地址
@Value("#{fileConfig.nginxServerPath}")
private String nginxServerPath;
private final String TYPE_DOWNLOAD = "download";
private final String TYPE_READ = "read";
@Autowired
private FileChunkService fileChunkService;
@Autowired
private FileEntityService fileEntityService;
private static final Logger log = LoggerFactory.getLogger(FastDFSFileHandler.class);
@Override
public String fileLocation() {
return "fastdfs";
}
@Override
public String fileUrlSchema() {
return "fastdfs";
}
@Override
public Result<String> save(MultipartFile file, FileSpace fileSpace, FileEntity fileEntity) {
try {
return Result.create(FastDFSUtil.uploadFile(fastdfsTrackerServerPath, file, fileEntity.getSuffix()));
} catch (MyException | IOException e) {
log.error("文件保存失败!filespace={},fileentity={}", JSON.toJSONString(fileSpace), JSON.toJSONString(fileEntity), e);
return Result.create(FileError.file_upload_fail);
}
}
@Override
public Result delete(FileEntity fileEntity,List<FileChunk> fileChunks) {
try {
List<String> fileUrs =new ArrayList<>();
if (CollectionUtils.isNotEmpty(fileChunks)){
//分片文件的url
fileUrs = fileChunks.stream().map(FileChunk::getUrl).collect(Collectors.toList());
}
if(null != fileEntity){
//非分片文件的url
fileUrs.add(fileEntity.getUrl());
}
if (CollectionUtils.isEmpty(fileUrs)) {
return Result.create(CommonError.forbidden, "未找到要删除的文件");
}
return FastDFSUtil.batchDeleteFile(fastdfsTrackerServerPath, fileUrs);
} catch (MyException | IOException e) {
log.error("文件删除失败!fileentity={}", JSON.toJSONString(fileEntity), e);
return Result.create(CommonError.internal_error);
}
}
@Override
public void download(HttpServletResponse response, String uri, FileEntity fileEntity) throws IOException {
downloadOrReadFile(response, uri, fileEntity, TYPE_DOWNLOAD);
}
@Override
public void readFile(HttpServletResponse response, String uri, FileEntity fileEntity) throws IOException {
downloadOrReadFile(response, uri, fileEntity, TYPE_READ);
}
@Override
public InputStream readFile(String uri, FileEntity fileEntity) throws IOException {
if (StringUtils.isBlank(nginxServerPath)) {
throw new MicroRuntimeException(CommonError.forbidden, "nginx访问fastdfs服务器地址未配置!");
}
List<String> fileUrls = new ArrayList<>();
if (isChunkFile(fileEntity, null)) {
List<String> chunkFileUrls = getChunkFileUrls(fileEntity, null);
if (CollectionUtils.isEmpty(chunkFileUrls)) {
throw new MicroRuntimeException(CommonError.forbidden, "未找到要分片的文件信息");
}
fileUrls.addAll(chunkFileUrls);
} else {
fileUrls.add(fileEntity.getUrl());
}
return FastDFSUtil.readFile(nginxServerPath, fileUrls);
}
private void downloadOrReadFile(HttpServletResponse response, String uri, FileEntity fileEntity, String type) throws IOException {
String filename = getFilename(uri, fileEntity);
try {
//分块合成
if (isChunkFile(fileEntity, uri)) {
List<String> fileUrls = getChunkFileUrls(fileEntity, uri);
if (CollectionUtils.isEmpty(fileUrls)) {
response.sendError(HttpStatus.SC_FORBIDDEN, "未找到要下载的分片文件");
return;
}
FastDFSUtil.mergeChunks(response, fastdfsTrackerServerPath, fileUrls, filename);
} else {
String url = getPath(uri);
if (StringUtils.equals(TYPE_READ, type) || (StringUtils.equals(TYPE_DOWNLOAD, type) && StringUtils.isBlank(nginxServerPath))) {
FastDFSUtil.downLoadFile(fastdfsTrackerServerPath, response, url, filename);
} else if (StringUtils.equals(TYPE_DOWNLOAD, type)) {
FastDFSUtil.downLoadFileByRedirect(nginxServerPath, response, url, filename);
} else {
throw new MicroRuntimeException(CommonError.forbidden, "获取实体文件失败");
}
}
String contentType = getFileContentType(fileEntity, filename);
response.setHeader("content-type", contentType);
response.setContentType(contentType);
} catch (MyException e) {
log.error("文件下载或读取失败uri={},filename={}", uri, filename, e);
response.sendError(HttpStatus.SC_INTERNAL_SERVER_ERROR, "文件下载或读取失败");
}
}
private List<String> getChunkFileUrls(FileEntity fileEntity, String url) {
String uploadid = getChunkFileUploadid(fileEntity, url);
if (StringUtils.isBlank(uploadid)) {
return null;
}
if (null == fileEntity) {
fileEntity = fileEntityService.getFileEntityByUploadId(uploadid);
if (null == fileEntity) {
return null;
}
}
List<FileChunk> fileChunks = fileChunkService.listFileChunkByFileid(fileEntity.getId());
if (CollectionUtils.isEmpty(fileChunks)) {
return null;
}
return fileChunks.stream().map(FileChunk::getUrl).collect(Collectors.toList());
}
}java
import com.commnetsoft.commons.Result;
import com.commnetsoft.commons.utils.StringUtils;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.exception.MicroRuntimeException;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.http.HttpStatus;
import org.csource.common.MyException;
import org.csource.fastdfs.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.*;
/**
* @className: FastDFSUtil 操作fastDFS服务器工具类
* @author: lijx
* @date: 2020/7/8 16:11
* @version: 1.0
*/
public class FastDFSUtil {
public static final String FASTDFS_URL_PREFIX = "fastdfs:///";
/**
* 获取操作远程文件服务器的对象
* @param fastdfsTrackerServerPath 远程跟踪服务器的地址
* @return org.csource.fastdfs.StorageClient
* @author lijx
* date 2020/7/8 16:18
*/
public static StorageClient getStorageClient(String fastdfsTrackerServerPath) throws MyException, IOException {
if (StringUtils.isBlank(fastdfsTrackerServerPath)) {
throw new MicroRuntimeException(CommonError.illegal_config, "未配置FastDFS服务器地址");
}
ClientGlobal.initByTrackers(fastdfsTrackerServerPath);
TrackerClient trackerClient = new TrackerClient();
TrackerServer trackerServer = trackerClient.getTrackerServer();
StorageServer storeStorage = trackerClient.getStoreStorage(trackerServer);
return new StorageClient(trackerServer, storeStorage);
}
/**
* 文件上传
* @param fastdfsTrackerServerPath 远程跟踪服务器的地址
* @param file 要上传的文件
* @param fileExtName 文件扩展名
* @return java.lang.String 返回文件地址(前缀/组名/文件地址,例如:fastdfs://group1/M00/00/00/wKgBeV8CgB6AOrWuAABHLD0PyPk795.jpg)
* @author lijx
* date 2020/7/8 16:26
*/
public static String uploadFile(String fastdfsTrackerServerPath, MultipartFile file, String fileExtName) throws MyException, IOException {
StorageClient storageClient = getStorageClient(fastdfsTrackerServerPath);
String[] result = storageClient.upload_file(file.getBytes(), fileExtName, null);
if (ArrayUtils.getLength(result) == 0) {
throw new MicroRuntimeException(CommonError.illegal_response, "文件上传到FastDFS服务器,返回的地址为空");
}
return FASTDFS_URL_PREFIX + StringUtils.join(result, "/");
}
/**
* 把分区块上传的文件块,合并成一个文件,放到response中
* @param response
* @param fastdfsTrackerServerPath 远程跟踪服务器的地址
* @param fileUrls 各个区块文件的地址(一定要按顺序)
* @param fileName 合并后的文件名称
* @return
* @author lijx
* date 2020/7/8 17:26
*/
public static void mergeChunks(HttpServletResponse response, String fastdfsTrackerServerPath, List<String> fileUrls, String fileName) throws MyException, IOException {
if (CollectionUtils.isEmpty(fileUrls)) {
response.sendError(HttpStatus.SC_FORBIDDEN, "下载的地址不能为空");
return;
}
StorageClient storageClient = getStorageClient(fastdfsTrackerServerPath);
if (StringUtils.isNotBlank(fileName)) {
response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
}
OutputStream os = response.getOutputStream();
byte[] bytes;
InputStream inputStream = null;
try {
for (String fileUrl : fileUrls) {
String[] groupAndFileUrlArr = getGroupAndFileUrlArr(fileUrl);
if (ArrayUtils.getLength(groupAndFileUrlArr) != 2) {
response.sendError(HttpStatus.SC_FORBIDDEN, "文件地址错误");
return;
}
bytes = storageClient.download_file(groupAndFileUrlArr[0], groupAndFileUrlArr[1]);
if (ArrayUtils.isEmpty(bytes)) {
throw new MicroRuntimeException(CommonError.notfound, "未读到指定地址的文件");
}
inputStream = new ByteArrayInputStream(bytes);
IOUtils.copy(inputStream, os);
}
} finally {
if (null != inputStream) inputStream.close();
if (null != os) os.close();
}
}
/**
* 文件下载(重定向,适用于客户端)
* @param nginxServerPath nginx服务器的地址
* @param response 下载响应到客户端
* @param fileUrl 文件存在在fastDFS的地址(例如:group1/M00/00/00/wKgBeV8CgB6AOrWuAABHLD0PyPk795.jpg)
* @param fileName 文件名,需要带扩展名(上传到fastDFS服务器的文件,名称自动会变成无需的字符串,保证不重复)
* @return void
* @author lijx
* date 2020/7/8 16:32
*/
public static void downLoadFileByRedirect(String nginxServerPath, HttpServletResponse response, String fileUrl, String fileName) throws IOException {
String[] groupAndFileUrlArr = getGroupAndFileUrlArr(fileUrl);
if (ArrayUtils.getLength(groupAndFileUrlArr) != 2) {
response.sendError(HttpStatus.SC_FORBIDDEN, "文件地址错误");
return;
}
if (StringUtils.isBlank(nginxServerPath)) {
response.sendError(HttpStatus.SC_FORBIDDEN, "未配置nginx服务器地址");
return;
}
if (!StringUtils.endsWith(nginxServerPath, "/")) {
nginxServerPath = new StringBuffer(nginxServerPath).append("/").toString();
}
String redirectUrl = new StringBuffer(nginxServerPath).append(groupAndFileUrlArr[0]).append("/").append(groupAndFileUrlArr[1])
.append("?attname=").append(URLEncoder.encode(fileName, "UTF-8")).toString();
response.sendRedirect(redirectUrl);
}
/**
* 文件下载(重定向,适用于服务端)
* @param fastdfsTrackerServerPath fastdfs跟踪服务器的地址
* @param response 下载响应到客户端
* @param fileUrl 文件存在在fastDFS的地址(例如:group1/M00/00/00/wKgBeV8CgB6AOrWuAABHLD0PyPk795.jpg)
* @param fileName 文件名,需要带扩展名(上传到fastDFS服务器的文件,名称自动会变成无需的字符串,保证不重复)
* @return void
* @author lijx
* date 2020/7/9 16:44
*/
public static void downLoadFile(String fastdfsTrackerServerPath, HttpServletResponse response, String fileUrl, String fileName) throws MyException, IOException {
if (StringUtils.isBlank(fileUrl)) {
response.sendError(HttpStatus.SC_FORBIDDEN, "下载的文件不能为空");
return;
}
mergeChunks(response, fastdfsTrackerServerPath, Arrays.asList(fileUrl), fileName);
}
/**
* 批量删除服务器的文件
* @param fastdfsTrackerServerPath fastdfs跟踪服务器的地址
* @param fileUrls 文件存在在fastDFS的地址(例如:group1/M00/00/00/wKgBeV8CgB6AOrWuAABHLD0PyPk795.jpg)
* @return com.commnetsoft.commons.Result<java.lang.Object>
* @author lijx
* date 2020/7/9 16:48
*/
public static Result batchDeleteFile(String fastdfsTrackerServerPath, Collection<String> fileUrls) throws MyException, IOException {
if (CollectionUtils.isEmpty(fileUrls)) {
return Result.create();
}
StorageClient storageClient = getStorageClient(fastdfsTrackerServerPath);
for (String fileUrl : fileUrls) {
String[] groupAndFileUrlArr = getGroupAndFileUrlArr(fileUrl);
if (ArrayUtils.getLength(groupAndFileUrlArr) != 2) {
return Result.create(CommonError.forbidden, "文件地址错误");
}
int result = storageClient.delete_file(groupAndFileUrlArr[0], groupAndFileUrlArr[1]);
if (0 != result) {
return Result.create(CommonError.illegal_response, "文件删除失败");
}
}
return Result.create();
}
/**
* explain: 读取文件
* @param nginxServerPath nginx服务器的地址
* @param fileUrls 文件存在在fastDFS的地址(例如:group1/M00/00/00/wKgBeV8CgB6AOrWuAABHLD0PyPk795.jpg)
* @author lijx
* @date 2020/12/17
*/
public static InputStream readFile(String nginxServerPath, List<String> fileUrls) throws IOException {
if (CollectionUtils.isEmpty(fileUrls)) {
throw new MicroRuntimeException(CommonError.forbidden, "读取的文件地址不能为空");
}
if (!StringUtils.endsWith(nginxServerPath, "/")) {
nginxServerPath = new StringBuffer(nginxServerPath).append("/").toString();
}
List<InputStream> inputStreams = new ArrayList<>();
InputStream inputStream;
URL url;
URLConnection uc;
for (String fileUrl : fileUrls) {
String[] groupAndFileUrlArr = getGroupAndFileUrlArr(fileUrl);
if (ArrayUtils.getLength(groupAndFileUrlArr) != 2) {
throw new MicroRuntimeException(CommonError.forbidden, "读取文件时,地址错误");
}
String path = new StringBuffer(nginxServerPath).append(groupAndFileUrlArr[0]).append("/").append(groupAndFileUrlArr[1]).toString();
url = new URL(path);
uc = url.openConnection();
//获取输入流
inputStream = uc.getInputStream();
if (null == inputStream) {
throw new MicroRuntimeException(CommonError.notfound, "未读到指定地址的文件");
}
inputStreams.add(inputStream);
}
return new SequenceInputStream(Collections.enumeration(inputStreams));
}
/**
* 截取符合条件的fastDFS服务文件地址
* @param fileUrl
* @return java.lang.String
* @author lijx
* date 2020/7/8 17:17
*/
public static String getFastDFSUrl(String fileUrl) {
if (StringUtils.isBlank(fileUrl)) {
return fileUrl;
}
if (StringUtils.contains(fileUrl, FASTDFS_URL_PREFIX)) {
return StringUtils.replace(fileUrl, FASTDFS_URL_PREFIX, "");
}
return fileUrl;
}
/**
* 拆分文件地址的group和文件地址
* @param fileUrl
* @return java.lang.String[]
* @author lijx
* date 2020/8/4 11:07
*/
public static String[] getGroupAndFileUrlArr(String fileUrl) {
String fastDFSUrl = getFastDFSUrl(fileUrl);
if (StringUtils.isBlank(fastDFSUrl)) {
return null;
}
return StringUtils.split(fastDFSUrl, "/", 2);
}
}http文件读取
java
import com.commnetsoft.file.model.FileEntity;
import com.commnetsoft.file.utils.IFileReadHandler;
import org.apache.http.HttpStatus;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
/**
* http文件 读取
* @ClassName HttpFileHandler
* @Author wuzm
* @Date 2020/7/8 14:09
* @Version 1.0
*/
@Component
public class HttpFileHandler implements IFileReadHandler {
@Override
public String fileUrlSchema() {
return "http,https";
}
@Override
public void download(HttpServletResponse response, String uri, FileEntity fileEntity) throws IOException {
response.sendRedirect(uri);
}
@Override
public void readFile(HttpServletResponse response, String uri, FileEntity fileEntity) throws IOException {
response.sendError(HttpStatus.SC_NOT_IMPLEMENTED);
}
@Override
public InputStream readFile(String uri, FileEntity fileEntity) throws IOException {
return null;
}
}idm文件控制程序
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.commons.utils.HttpUtils;
import com.commnetsoft.commons.utils.StringUtils;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.exception.MicroException;
import com.commnetsoft.exception.MicroRuntimeException;
import com.commnetsoft.file.constant.FileSystemConstant;
import com.commnetsoft.file.model.FileChunk;
import com.commnetsoft.file.model.FileEntity;
import com.commnetsoft.file.model.FileSpace;
import com.commnetsoft.file.service.FileChunkService;
import com.commnetsoft.file.utils.IFileReadHandler;
import com.commnetsoft.file.utils.IFileWriteHandler;
import com.commnetsoft.file.utils.IdmFileHelper;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpException;
import org.apache.http.HttpStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @ClassName IdmFileHandler
* @Author wuzm
* @Date 2020/6/30 19:21
* @Version 1.0
*/
@Component
@RefreshScope
public class IdmFileHandler implements IFileWriteHandler, IFileReadHandler {
private static final Logger log = LoggerFactory.getLogger(IdmFileHandler.class);
public static final String IDM_URL_PREFIX = "idm:///";
//idm是否允许跨域
@Value("#{fileConfig.idmEnableCros}")
private Boolean idmEnableCros;
@Autowired
private IdmFileHelper idmFileHelper;
@Autowired
private FileChunkService fileChunkService;
@Override
public String fileLocation() {
return "idm";
}
@Override
public String fileUrlSchema() {
return "idm";
}
@Override
public Result<String> save(MultipartFile file, FileSpace fileSpace, FileEntity fileEntity) {
try {
Integer expires = 0;
if (null != fileEntity.getExpiretime()) {
expires = 1;
}
String uri = idmFileHelper.upload(file, fileEntity.getName(), expires);
return Result.create(uri);
} catch (IOException | HttpException e) {
return Result.create(CommonError.internal_error, e.getMessage());
} catch (MicroException e) {
return Result.create(e);
}
}
@Override
public Result delete(FileEntity fileEntity,List<FileChunk>fileChunks) {
return Result.create();
}
@Override
public void download(HttpServletResponse response, String uri, FileEntity fileEntity) {
try {
uri = getPath(uri);
if(idmEnableCros){
response.sendRedirect(idmFileHelper.getIdmDownloadUrl(uri));
}else{
readFile(response, uri, fileEntity);
}
} catch (Exception e) {
log.error("文件下载失败uri={}", uri, e);
}
}
@Override
public void readFile(HttpServletResponse response, String uri, FileEntity fileEntity) throws IOException {
String url = idmFileHelper.getIdmDownloadUrl(getPath(uri));
URL realUrl = new URL(url);
HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();
HttpUtils.setHeader(conn, null);
// 发送POST请求必须设置如下两行
conn.setDoOutput(false);
conn.setDoInput(true);
// 定义BufferedReader输入流来读取URL的响应
int statusCode = conn.getResponseCode();
if(HttpStatus.SC_OK == statusCode){
Map<String, List<String>> headerFields = conn.getHeaderFields();
if(MapUtils.isNotEmpty(headerFields)){
for (Map.Entry<String, List<String>> headerFieldEntity : headerFields.entrySet()) {
response.setHeader(headerFieldEntity.getKey(), CollectionUtils.isNotEmpty(headerFieldEntity.getValue()) ? headerFieldEntity.getValue().get(0) : "");
}
}
IOUtils.copy(conn.getInputStream(), response.getOutputStream());
return ;
}
throw new IOException( url + " 请求失败:" + statusCode);
}
@Override
public InputStream readFile(String uri, FileEntity fileEntity) throws IOException {
if (FileSystemConstant.TRUE_NUM.equals(fileEntity.getChunk())){
return readChunkFile(fileEntity);
}
String url = "/" + StringUtils.substringAfter(fileEntity.getUrl(), IDM_URL_PREFIX);
url = idmFileHelper.getIdmDownloadUrl(url);
return HttpUtils.get(url,null);
}
private InputStream readChunkFile(FileEntity fileEntity) throws IOException {
FileChunk query = new FileChunk();
query.setFileid(fileEntity.getId());
List<FileChunk> fileChunks = fileChunkService.queryList(query);
if (CollectionUtils.isEmpty(fileChunks)){
throw new MicroRuntimeException(CommonError.notfound,"分片文件不存在");
}
List<String> chunkUrls = fileChunks.stream().map(FileChunk::getUrl).collect(Collectors.toList());
byte [] result=null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
for (String chunkUrl : chunkUrls) {
String url = "/" + StringUtils.substringAfter(chunkUrl, IDM_URL_PREFIX);
url = idmFileHelper.getIdmDownloadUrl(url);
InputStream inputStream = HttpUtils.get(url, null);
result=new byte[inputStream.available()];
baos.write(result,0,inputStream.read(result));
}
return new ByteArrayInputStream(baos.toByteArray());
}
}java
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.commnetsoft.commons.utils.HttpUtils;
import com.commnetsoft.commons.utils.StringUtils;
import com.commnetsoft.commons.utils.UUIDUtils;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.exception.MicroException;
import com.commnetsoft.exception.MicroRuntimeException;
import org.apache.commons.io.FileUtils;
import org.apache.http.HttpException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* IDM文件工具类
* @author sunwen
* @since 2019/12/26
*/
@Component
@RefreshScope
public class IdmFileHelper {
//idm地址
@Value("#{fileConfig.idmHost}")
private String idmHost;
//idm文件存放目录ID
@Value("#{fileConfig.idmDir}")
private Integer idmDir;
//idm临时文件存放目录ID
@Value("#{fileConfig.idmTempDir}")
private Integer idmTempDir;
public String getIdmDownloadUrl(String path) {
return idmHost + path;
}
/**
* 上传文件到IDM 返回文件下载地址
* @author sunwen
* @since 2019/12/26
*/
public String upload(MultipartFile file, String filename, Integer expires) throws IOException, HttpException, MicroException {
Integer dirid = expires != null && expires > 0 ? idmTempDir : idmDir;
if(dirid == null){
throw new MicroException(CommonError.illegal_config, "未配置IDM文件目录");
}
if(StringUtils.isEmpty(filename)){
filename = file.getOriginalFilename();
}
File localFile = null;
try {
File path = new File(System.getProperty("java.io.tmpdir"));
localFile = new File(path, UUIDUtils.generate() + ".temp");
FileUtils.copyInputStreamToFile(file.getInputStream(), localFile);
Map<String, Object> params = new HashMap<>();
params.put("dirid", dirid);
params.put("file", HttpUtils.fromFile(localFile, filename));
String result = HttpUtils.postMultipart(idmHost + "/sys/file/upload", params);
if(StringUtils.isNotEmpty(result)){
JSONObject obj = JSON.parseObject(result);
if("0".equals(obj.getString("code"))){
String uri = "idm:///sys/file/download/" + obj.getInteger("attr");
/*if(StringUtils.isNotEmpty(filename)){
uri += "?filename=" + URLEncoder.encode(filename, StandardCharsets.UTF_8.toString());
}*/
return uri;
}else{
throw new MicroException(CommonError.illegal_response, obj.getString("msg"));
}
}
throw new MicroException(CommonError.unknown);
}finally {
FileUtils.deleteQuietly(localFile);
}
}
/**
* 根据文件id,获取文件名称
* @param fileid
* @return java.lang.String
* @author lijx
* date 2020/8/6 13:39
*/
public String getFileNameByFileId(Integer fileid) throws IOException {
if (null == fileid) {
throw new MicroRuntimeException(CommonError.illegal_args, "文件id不能为空!");
}
if (StringUtils.isBlank(idmHost)) {
throw new MicroRuntimeException(CommonError.illegal_config, "未配置idm地址!");
}
String result = HttpUtils.sendGet(idmHost + "/sys/file/getnames?ids=" + fileid, null);
if (StringUtils.isBlank(result)) {
throw new MicroRuntimeException(CommonError.unknown, "调用idm接口,返回值为空");
}
List<Map> maps = JSON.parseArray(result, Map.class);
if (maps.size() == 0 || null == maps.get(0).get("text")) {
throw new MicroRuntimeException(CommonError.illegal_response, "未查询到文件信息");
}
return maps.get(0).get("text").toString();
}
}本地文件处理类
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.commons.utils.StringUtils;
import com.commnetsoft.commons.utils.UUIDUtils;
import com.commnetsoft.commons.utils.UriUtil;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.exception.MicroRuntimeException;
import com.commnetsoft.file.constant.FileSystemConstant;
import com.commnetsoft.file.model.FileChunk;
import com.commnetsoft.file.model.FileEntity;
import com.commnetsoft.file.model.FileSpace;
import com.commnetsoft.file.service.FileChunkService;
import com.commnetsoft.file.utils.IFileReadHandler;
import com.commnetsoft.file.utils.IFileWriteHandler;
import org.apache.catalina.connector.ClientAbortException;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
/**
* 本地文件处理类
*
* @ClassName LocalFileHandler
* @Author wuzm
* @Date 2020/6/30 19:21
* @Version 1.0
*/
@Component
@RefreshScope
public class LocalFileHandler implements IFileWriteHandler, IFileReadHandler {
private static final Logger log = LoggerFactory.getLogger(LocalFileHandler.class);
public static final String LOCAL_URL_PREFIX = "local:///";
@Autowired
private FileChunkService fileChunkService;
//本地文件保存地址
@Value("#{fileConfig.localSavePath}")
private String localSavePath;
@Override
public String fileLocation() {
return "local";
}
@Override
public String fileUrlSchema() {
return "local";
}
@Override
public Result<String> save(MultipartFile file, FileSpace fileSpace, FileEntity fileEntity) {
if (StringUtils.isBlank(localSavePath)) {
return Result.create(CommonError.illegal_config, "文件上传路径配置错误");
}
String localPath = UriUtil.subUriLastSlash(localSavePath);
StringBuffer realPath = new StringBuffer();
realPath.append(localPath);
realPath.append(File.separatorChar);
realPath.append(fileSpace.getNamespace());
realPath.append(File.separatorChar);
realPath.append(fileSpace.getSpacecode());
//再加一层目录做文件分散,防止单个文件夹下数量太大
realPath.append(File.separatorChar);
realPath.append(getFileSubDir(fileEntity));
//判断文件保存的目录是否存在
File catalog = new File(realPath.toString());
if (!catalog.exists()) {
catalog.mkdirs();
}
String filename = "";
InputStream inputStream =null;
FileOutputStream outputStream =null;
try {
if (FileSystemConstant.TRUE_NUM.equals(fileEntity.getChunk())) {
filename = UUIDUtils.generate()+((StringUtils.isBlank(fileEntity.getSuffix())) ? "" : "." + fileEntity.getSuffix());
} else {
filename = fileEntity.getUploadid()+((StringUtils.isBlank(fileEntity.getSuffix())) ? "" : "." + fileEntity.getSuffix());
}
String s = LOCAL_URL_PREFIX + realPath + File.separatorChar + filename;
String url = s.replaceAll("\\\\", "/");
inputStream = file.getInputStream();
File uploadFile = new File(catalog, filename);
outputStream = new FileOutputStream(uploadFile);
IOUtils.copy(inputStream, outputStream);
return Result.create(url);
} catch (IOException e) {
log.error("文件上传失败!", e);
return Result.create(CommonError.internal_error, "文件上传失败");
}finally {
if (inputStream !=null && outputStream != null){
try {
inputStream.close();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private String getFileSubDir(FileEntity fileEntity){
String subDir = "00";
if(null != fileEntity){
if (StringUtils.isNotBlank(fileEntity.getEncryptvalue())) {
subDir = (fileEntity.getEncryptvalue().hashCode() & 0xf) + "";
} else if(StringUtils.isNotBlank(fileEntity.getChunkencryptvalue())){
subDir = (fileEntity.getChunkencryptvalue().hashCode() & 0xf) + "";
}
}
return StringUtils.leftPad(subDir, 2, "0");
}
@Override
public Result delete(FileEntity fileEntity,List<FileChunk> fileChunks) {
List<String> urls = new ArrayList<>();
if(null != fileEntity){
urls.add(fileEntity.getUrl());
}
if(CollectionUtils.isNotEmpty(fileChunks)){
for (FileChunk fileChunk : fileChunks) {
urls.add(fileChunk.getUrl());
}
}
return deleteFileByUrls(urls);
}
@Override
public void download(HttpServletResponse response, String uri, FileEntity fileEntity) throws IOException {
String filename = getFilename(uri, fileEntity);
try {
//判断先合并分片文件还是直接下载
choose(response, uri, fileEntity, filename);
} catch (IOException e) {
log.error("文件下载失败uri={},filename={}", uri, filename, e);
response.sendError(HttpStatus.SC_INTERNAL_SERVER_ERROR, "下载文件失败");
}
}
@Override
public void readFile(HttpServletResponse response, String uri, FileEntity fileEntity) throws IOException {
download(response, uri, fileEntity);
}
private void choose(HttpServletResponse response, String uri, FileEntity fileEntity, String filename) throws IOException {
//分块合成
if (FileSystemConstant.TRUE_NUM.equals(fileEntity.getChunk())) {
List<FileChunk> fileChunks = fileChunkService.listFileChunkByFileid(fileEntity.getId());
if (CollectionUtils.isEmpty(fileChunks)) {
response.sendError(HttpStatus.SC_NOT_FOUND, "找不到合成文件的分片");
}
mergeChunks(response, fileChunks, fileEntity,filename);
} else {
downLoadFile(response, uri, fileEntity,filename);
}
}
private void mergeChunks(HttpServletResponse response, List<FileChunk> fileChunks, FileEntity fileEntity, String filename) throws IOException {
String contentType = getFileContentType(fileEntity, filename);
response.setHeader("content-type", contentType);
response.setContentType(contentType);
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
OutputStream os = response.getOutputStream();
List<String> fileUrls = fileChunks.stream().map(FileChunk::getUrl).collect(Collectors.toList());
InputStream inputStream = null;
try {
for (String fileUrl : fileUrls) {
fileUrl = StringUtils.substringAfter(fileUrl, LOCAL_URL_PREFIX);
File file = new File(fileUrl);
if (!file.exists()) {
throw new MicroRuntimeException(CommonError.notfound, "未读到指定地址的文件");
}
inputStream = new FileInputStream(file);
IOUtils.copy(inputStream, os);
}
} finally {
if (null != inputStream) inputStream.close();
if (null != os) os.close();
}
}
public void downLoadFile(HttpServletResponse response, String uri, FileEntity fileEntity,String filename) {
FileInputStream fis = null;
try {
String location = StringUtils.substringAfter(uri, LOCAL_URL_PREFIX);
File file = new File(location);
if (!file.exists()) {
log.error("文件不存在 filename={}", filename);
return;
}
fis = new FileInputStream(file);
String contentType = getFileContentType(fileEntity, filename);
response.setHeader("content-type", contentType);
response.setContentType(contentType);
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
IOUtils.copy(fis, response.getOutputStream());
response.flushBuffer();
}catch (ClientAbortException cae){
log.error("客户端提前关闭异常,uri={}", uri, cae);
}catch (IOException e) {
log.error("文件下载失败! uri={}", uri, e);
try {
response.sendError(HttpStatus.SC_INTERNAL_SERVER_ERROR, "下载文件失败");
} catch (IOException ex) {
log.error("发送错误信息失败! uri={}", uri, ex);
}
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
log.error("文件下载失败! uri={}", uri, e);
}
}
}
}
@Override
public InputStream readFile(String uri, FileEntity fileEntity) throws IOException {
if (FileSystemConstant.TRUE_NUM.equals(fileEntity.getChunk())) {
FileChunk query = new FileChunk();
query.setFileid(fileEntity.getId());
List<FileChunk> fileChunks = fileChunkService.queryList(query);
List<String> fileUrls = fileChunks.stream().map(FileChunk::getUrl).collect(Collectors.toList());
List<InputStream> inputStreams = new ArrayList<>();
InputStream inputStream = null;
for (String fileUrl : fileUrls) {
fileUrl = StringUtils.substringAfter(fileUrl, LOCAL_URL_PREFIX);
File file = new File(fileUrl);
if (!file.exists()) {
throw new MicroRuntimeException(CommonError.notfound, "未读到指定地址的文件");
}
inputStream = new FileInputStream(file);
inputStreams.add(inputStream);
}
return new SequenceInputStream(Collections.enumeration(inputStreams));
}
String url = StringUtils.substringAfter(fileEntity.getUrl(), LOCAL_URL_PREFIX);
File file = new File(url);
if (!file.exists()) {
throw new MicroRuntimeException(CommonError.notfound, "未读到指定地址的文件");
}
return new FileInputStream(file);
}
private byte[] readChunkFile(List<FileChunk> fileChunks) throws IOException {
List<String> fileUrls = fileChunks.stream().map(FileChunk::getUrl).collect(Collectors.toList());
byte[] result = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
for (String fileUrl : fileUrls) {
fileUrl = StringUtils.substringAfter(fileUrl, LOCAL_URL_PREFIX);
File file = new File(fileUrl);
if (!file.exists()) {
throw new MicroRuntimeException(CommonError.notfound, "未读到指定地址的文件");
}
InputStream inputStream = new FileInputStream(file);
result = new byte[inputStream.available()];
baos.write(result, 0, inputStream.read(result));
}
return baos.toByteArray();
}
private Result deleteFileByUrls(List<String> urls){
if (CollectionUtils.isEmpty(urls)){
return Result.create();
}
for (String url : urls){
String fileUrl = StringUtils.substringAfter(url, LOCAL_URL_PREFIX);
if(StringUtils.isBlank(fileUrl)){
log.error("文件路径不合法,{}", url);
return Result.create(CommonError.internal_error, "文件路径不合法");
}
File file = new File(fileUrl);
if (!file.exists()){
continue;
}
//删除真实的文件
boolean delete = file.delete();
if (delete){
continue;
}else{
log.error("文件删除失败,文件路径={}", url);
return Result.create(CommonError.internal_error, "文件删除失败");
}
}
return Result.create();
}
}OSS文件处理
java
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.*;
import com.commnetsoft.commons.Result;
import com.commnetsoft.commons.utils.StringUtils;
import com.commnetsoft.commons.utils.UUIDUtils;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.file.constant.FileSystemConstant;
import com.commnetsoft.file.model.FileChunk;
import com.commnetsoft.file.model.FileEntity;
import com.commnetsoft.file.model.FileSpace;
import com.commnetsoft.file.service.FileChunkService;
import com.commnetsoft.file.utils.IFileReadHandler;
import com.commnetsoft.file.utils.IFileWriteHandler;
import org.apache.commons.collections.CollectionUtils;
import org.apache.http.HttpStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
/**
* @ClassName OssFileHandler
* @Author wujs
* @Date 2020/9/18 15:13
* @Version 1.0
*/
@Component
@RefreshScope
public class OssFileHandler implements IFileWriteHandler, IFileReadHandler {
private static final Logger log = LoggerFactory.getLogger(OssFileHandler.class);
//oss文件服务器保存地址
@Value("#{fileConfig.ossSavePath}")
private String endpoint;
//oss文件服务器accessKeyId
@Value("#{fileConfig.accessKeyId}")
private String accessKeyId;
//oss文件服务器accessKeySecret
@Value("#{fileConfig.accessKeySecret}")
private String accessKeySecret;
//oss文件服务器bucketName
@Value("#{fileConfig.bucketName}")
private String bucketName;
public static final String OSS_URL_PREFIX = "oss:///";
@Autowired
private FileChunkService fileChunkService;
@Override
public String fileUrlSchema() {
return "oss";
}
@Override
public String fileLocation() {
return "oss";
}
@Override
public Result<String> save(MultipartFile file, FileSpace fileSpace, FileEntity fileEntity) {
if (file == null) {
return Result.create(CommonError.illegal_args, "文件不能为空");
}
String fileName = null;
//新文件名称
if (FileSystemConstant.TRUE_NUM.equals(fileEntity.getChunk())) {
fileName = UUIDUtils.generate() + "." + fileEntity.getSuffix();
} else {
fileName = fileEntity.getUploadid() + "." + fileEntity.getSuffix();
}
//获取文件类型
String fileType = file.getContentType();
InputStream inputStream = null;
try {
inputStream = file.getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
//上传文件
String url = putFile(inputStream, fileType, fileName, fileEntity);
if (StringUtils.isNotBlank(url)) {
return Result.create(url);
} else {
return Result.create(CommonError.internal_error, "文件上传到oss文件服务器失败");
}
}
private String putFile(InputStream input, String fileType, String fileName, FileEntity fileEntity) {
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
try {
// 创建上传Object的Metadata
ObjectMetadata meta = new ObjectMetadata();
// 设置上传内容类型
meta.setContentType(fileType);
//被下载时网页的缓存行为
meta.setCacheControl("no-cache");
//获取原文件名
String filename = fileEntity.getName();
//设置文件上传时的请求头信息,这样上传返回文件存储的url路径,通过url路径直接下载就可以得到源文件名而不是加密的随机码。
meta.setContentDisposition("attachment;filename=\"" + filename + "\"");
//创建上传请求
PutObjectRequest request = new PutObjectRequest(bucketName, fileName, input, meta);
//上传文件
ossClient.putObject(request);
//设置url过期时间
Date expiration = null;
if (null != fileEntity.getExpiretime()) {
expiration = fileEntity.getExpiretime();
} else {
//100年
expiration = new Date(new Date().getTime() + 1000 * 3600 * 24 * 365 * 100);
}
//获取上传成功的文件地址
URL url = ossClient.generatePresignedUrl(bucketName, fileName, expiration);
//截取url,不要accessKeyId等信息
String[] str = url.toString().split("\\?");
if (StringUtils.isNotBlank(str[0])) {
return OSS_URL_PREFIX + str[0];
} else {
return null;
}
} catch (OSSException e) {
log.error("文件上传失败!", e);
return null;
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
}
@Override
public void download(HttpServletResponse response, String uri, FileEntity fileEntity) throws IOException {
String filename = getFilename(uri, fileEntity);
try {
//判断先合并分片文件还是直接下载
choose(response, uri, fileEntity, filename);
} catch (IOException e) {
log.error("文件下载失败uri={},filename={}", uri, filename, e);
response.sendError(HttpStatus.SC_INTERNAL_SERVER_ERROR, "下载文件失败");
}
}
private void choose(HttpServletResponse response, String uri, FileEntity fileEntity, String filename) throws IOException {
//分块合成
if (FileSystemConstant.TRUE_NUM.equals(fileEntity.getChunk())) {
List<FileChunk> fileChunks = fileChunkService.listFileChunkByFileid(fileEntity.getId());
if (CollectionUtils.isEmpty(fileChunks)) {
response.sendError(HttpStatus.SC_NOT_FOUND, "找不到合成文件的分片");
}
mergeChunks(response, fileChunks, fileEntity, filename);
} else {
downloadFile(response, uri, fileEntity, filename);
}
}
/**
* 合并分片
*
* @param response
* @param fileChunks
* @param fileEntity
* @param filename
* @return void
* @author wujs
* @date 2020/9/22 14:17
*/
private void mergeChunks(HttpServletResponse response, List<FileChunk> fileChunks, FileEntity fileEntity, String filename) {
String downName = null;
OutputStream outputStream = null;
try {
List<String> fileUrls = fileChunks.stream().map(FileChunk::getUrl).collect(Collectors.toList());
downName = new String(fileEntity.getName().getBytes("gb2312"), "ISO8859-1");
String contentType = getFileContentType(fileEntity, filename);
response.setHeader("content-type", contentType);
response.setContentType(contentType);
//设置文件下载名称
response.addHeader("Content-Disposition", "attachment;filename=" + downName);
outputStream = response.getOutputStream();
byte[] bytes = readChunkFile(fileUrls);
outputStream.write(bytes);
log.info("《downName={}》下载成功", downName);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
outputStream.close();
} catch (IOException e) {
log.error("IO流关闭失败");
e.printStackTrace();
}
}
}
private byte[] readChunkFile(List<String> fileUrls) throws IOException {
InputStream inputStream = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
for (String fileUrl : fileUrls) {
String fileName = fileUrl.substring(fileUrl.lastIndexOf('/') + 1, fileUrl.length());
OSSObject object = ossClient.getObject(bucketName, fileName);
inputStream = new BufferedInputStream(object.getObjectContent());
byte[] buffBytes = new byte[1024];
int read = 0;
while ((read = inputStream.read(buffBytes)) != -1) {
baos.write(buffBytes, 0, read);
}
}
inputStream.close();
baos.close();
ossClient.shutdown();
return (baos.toByteArray());
}
/**
* 下载文件
*
* @param response
* @param uri
* @param fileEntity
* @param filename
* @return void
* @author wujs
* @date 2020/9/22 14:18
*/
public void downloadFile(HttpServletResponse response, String uri, FileEntity fileEntity, String filename) {
BufferedInputStream input = null;
OutputStream outputStream = null;
try {
String fileName = fileEntity.getUploadid() + "." + fileEntity.getSuffix();
String downName = new String(fileEntity.getName().getBytes("gb2312"), "ISO8859-1");
String contentType = getFileContentType(fileEntity, filename);
response.setHeader("content-type", contentType);
response.setContentType(contentType);
//设置文件下载名称
response.addHeader("Content-Disposition", "attachment;filename=" + downName);
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
OSSObject object = ossClient.getObject(bucketName, fileName);
byte[] buffBytes = new byte[1024];
input = new BufferedInputStream(object.getObjectContent());
outputStream = response.getOutputStream();
int read = 0;
while ((read = input.read(buffBytes)) != -1) {
outputStream.write(buffBytes, 0, read);
}
log.info("《downName={}》下载成功", downName);
outputStream.flush();
ossClient.shutdown();
} catch (IOException ex) {
log.info("文件下载失败");
ex.printStackTrace();
} finally {
try {
if (outputStream != null) {
outputStream.close();
}
if (input != null) {
input.close();
}
} catch (IOException e) {
log.error("io流关闭失败");
e.printStackTrace();
}
}
}
@Override
public void readFile(HttpServletResponse response, String uri, FileEntity fileEntity) throws IOException {
download(response, uri, fileEntity);
}
@Override
public InputStream readFile(String uri, FileEntity fileEntity) throws IOException {
if (FileSystemConstant.TRUE_NUM.equals(fileEntity.getChunk())) {
FileChunk query = new FileChunk();
query.setFileid(fileEntity.getId());
List<FileChunk> fileChunks = fileChunkService.queryList(query);
List<String> fileUrls = fileChunks.stream().map(FileChunk::getUrl).collect(Collectors.toList());
byte[] bytes = readChunkFile(fileUrls);
return new ByteArrayInputStream(bytes);
} else {
String fileName = fileEntity.getUploadid() + "." + fileEntity.getSuffix();
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
OSSObject object = ossClient.getObject(bucketName, fileName);
return object.getObjectContent();
}
}
@Override
public Result delete(FileEntity fileEntity, List<FileChunk> fileChunks) {
List<String> urls = new ArrayList<>();
if (CollectionUtils.isNotEmpty(fileChunks)) {
for (FileChunk fileChunk : fileChunks) {
urls.add(fileChunk.getUrl());
}
}
if (null != fileEntity) {
urls.add(fileEntity.getUrl());
}
return deleteFileByUrls(urls);
}
/**
* 删除oss文件服务器上的文件
*
* @param urls
* @return com.commnetsoft.commons.Result
* @author wujs
* @date 2020/9/22 14:53
*/
private Result deleteFileByUrls(List<String> urls) {
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
ArrayList<String> fileNames = new ArrayList<>();
String fileName = null;
try {
//根据url获取fileName,通过filename删除oss服务器上的文件
for (String fileUrl : urls) {
fileName = fileUrl.substring(fileUrl.lastIndexOf('/') + 1, fileUrl.length());
fileNames.add(fileName);
}
DeleteObjectsRequest request = new DeleteObjectsRequest(bucketName).withKeys(fileNames);
ossClient.deleteObjects(request);
return Result.create("删除文件成功");
} catch (OSSException oe) {
oe.printStackTrace();
throw new RuntimeException("OSS服务异常:", oe);
} catch (ClientException ce) {
ce.printStackTrace();
throw new RuntimeException("OSS客户端异常:", ce);
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
}
}项目启动时将处理程序存入map
java
import com.commnetsoft.commons.utils.StringUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* @ClassName FileHandlerFactory
* @Author wuzm
* @Date 2020/6/30 19:20
* @Version 1.0
*/
@Component
public class FileHandlerFactory implements ApplicationContextAware {
private static Map<String, IFileWriteHandler> fileWriteHandlerMap;
private static Map<String, IFileReadHandler> fileReadHandlerMap;
private static Set<String> fileLocationList; //支持的所有文件存储类型
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
Map<String, IFileWriteHandler> fileWriteMap = applicationContext.getBeansOfType(IFileWriteHandler.class);
fileWriteHandlerMap = new HashMap<>();
fileLocationList = new HashSet<>();
fileWriteMap.forEach((key, value) -> {
fileWriteHandlerMap.put(value.fileLocation(), value);
fileLocationList.add(value.fileLocation());
});
Map<String, IFileReadHandler> fileReadMap = applicationContext.getBeansOfType(IFileReadHandler.class);
fileReadHandlerMap = new HashMap<>();
fileReadMap.forEach((key, value) -> {
String schemeStr = value.fileUrlSchema();
String[] schemes = StringUtils.split(schemeStr, ",");
if (ArrayUtils.isNotEmpty(schemes)) {
for (String scheme : schemes) {
fileReadHandlerMap.put(scheme, value);
}
}
});
}
public static IFileWriteHandler getFileWriteHandler(String handlerType) {
return fileWriteHandlerMap.get(handlerType);
}
public static IFileReadHandler getFileReadHandler(String scheme) {
return fileReadHandlerMap.get(scheme);
}
public static Set<String> getFileLocationList() {
return fileLocationList;
}
}file工具类
java
import com.commnetsoft.commons.utils.DateUtils;
import com.commnetsoft.commons.utils.FileUtils;
import com.commnetsoft.commons.utils.StringUtils;
import com.commnetsoft.commons.utils.UUIDUtils;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.exception.MicroException;
import com.commnetsoft.file.MockMultipartFile;
import com.commnetsoft.file.constant.FileSystemConstant;
import com.commnetsoft.file.model.FileSpace;
import com.commnetsoft.file.utils.filehandlerimpl.HttpFileHandler;
import com.commnetsoft.file.utils.filehandlerimpl.IdmFileHandler;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.FileNameMap;
import java.net.URI;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.Date;
/**
* @ClassName FileUtil
* @Author wuzm
* @Date 2020/8/6 15:45
* @Version 1.0
*/
public class FileUtil {
/**
* 是否为合法的文件系统地址,uploadid或者file://uploadid是为合法的
* @param uri
* @return boolean
* @author wuzm
* @date 2020/8/7
*/
public static boolean isFileSystemUri(String uri) {
if (StringUtils.isBlank(uri)) {
return false;
}
return StringUtils.startsWithIgnoreCase(uri, FileSystemConstant.FILE_NAMESPACE) || UUIDUtils.isUuid(uri);
}
/**
* 是否为合法的文件读取地址判断
* 只允许idm:///或file://开头以及uploadid的格式
* @param uri 文件路径
* @return boolean true 允许的,false 不允许的
* @author wuzm
* @date 2020/8/6
*/
public static boolean isLegalReadUri(String uri) {
if(isFileSystemUri(uri)){
return true;
}
return StringUtils.startsWithIgnoreCase(uri, new IdmFileHandler().fileUrlSchema());
}
/**
* 是否是合法的下载地址
* 允许idm:///或file://或http://或https://开头以及uploadid的格式
* @param uri 文件路径
* @return boolean
* @author wuzm
* @date 2020/8/6
*/
public static boolean isLegalDownloadUri(String uri){
if(isLegalReadUri(uri)){
return true;
}
return StringUtils.startsWithIgnoreCase(uri, new HttpFileHandler().fileUrlSchema().split(",")[0])
|| StringUtils.startsWithIgnoreCase(uri, new HttpFileHandler().fileUrlSchema().split(",")[1]);
}
/**
* 将File写到response中
* @param response
* @param file
* @return void
* @author lijx
* date 2020/8/20 8:52
*/
public static void fileToResponse(HttpServletResponse response, File file) throws IOException {
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
byte[] fileByte = new byte[bis.available()];
bis.read(fileByte);
String fileName = file.getName();
if (StringUtils.isNotBlank(fileName)) {
response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
}
OutputStream outputStream = response.getOutputStream();
outputStream.write(fileByte);
if (null != fis) fis.close();
if (null != bis) bis.close();
if (null != outputStream) {
outputStream.flush();
outputStream.close();
}
}
/**
* 将File转换成MultipartFile
* @param file
* @return org.springframework.web.multipart.MultipartFile
* @author lijx
* date 2020/8/20 8:50
*/
public static MultipartFile fromFile(File file) throws IOException {
MockMultipartFile multipartFile = null;
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
FileNameMap fileNameMap = URLConnection.getFileNameMap();
String contentType = fileNameMap.getContentTypeFor(file.getName());
multipartFile = new MockMultipartFile("file", file.getName(), contentType, fis);
} finally {
if (null != fis) fis.close();
}
return multipartFile;
}
/**
* 把文件输入流转inputStream换成文件File
* @param inputStream
* @param fileName
* @return java.io.File
* @author lijx
* date 2020/8/21 11:09
*/
public static File inputStreamToFile(InputStream inputStream, String fileName) throws IOException {
if (StringUtils.isBlank(fileName)) {
fileName = UUIDUtils.generate();
}
if (!StringUtils.contains(fileName, ".")) {
fileName += ".tmp";
}
File tempDirPath = new File(System.getProperty("java.io.tmpdir"));
File tempFile = new File(tempDirPath, fileName);
FileUtils.copyToFile(inputStream, tempFile);
return tempFile;
}
/**
* 获取文件名称
* 如果传入的文件名不带后缀,则取源文件的文件名后缀
* 如果传入的文件名为空,则直接返回源文件名
* 如果传入的文件名后缀与源文件的后缀不一样,则加上源文件的后缀
*
* @param filename 文件名
* @param originalFilename 源文件名
* @return java.lang.String
* @author wuzm
* @date 2020/7/31
*/
public static String getFilename(String filename, String originalFilename) {
if (StringUtils.isBlank(filename)) {
return originalFilename;
} else {
filename = StringUtils.trim(filename);
String newFileSuffix = FileUtils.getSuffix(filename);
String sourceSuffix = FileUtils.getSuffix(originalFilename);
if (StringUtils.isBlank(newFileSuffix)) {
if (StringUtils.isBlank(sourceSuffix)) {
return filename;
}else{
return filename + "." + sourceSuffix;
}
}else{
if (StringUtils.isBlank(sourceSuffix)) {
return filename;
}else if(StringUtils.equals(newFileSuffix,sourceSuffix)){
return filename;
}else{
return filename + "." + sourceSuffix;
}
}
}
}
/**
* 获取MultipartFile的文件名
* @param file
* @return java.lang.String
* @author lijx
* date 2020/8/21 14:34
*/
public static String getFileName(MultipartFile file) {
if (null == file) {
return "";
}
if (StringUtils.isNotBlank(file.getOriginalFilename())) {
return file.getOriginalFilename();
}
return file.getName();
}
/**
* 修改文件后缀
* @Param name
* @Param suffix
* @Return java.lang.String
* @Author wuzm
* Date 2019/12/17 14:09
*/
public static String changeFileNameToTargetSuffix(String name,String suffix){
if (StringUtils.startsWith(suffix, ".")) {
suffix = StringUtils.substringAfter(suffix, ".");
}
String prefixName = StringUtils.substringBeforeLast(name, ".");
return prefixName + "." +suffix;
}
/**
* 将文件路径转成文件上传Id
*
* @param uri 文件路径
* @return java.lang.String
* @author wuzm
* @date 2020/7/31
*/
public static String getUploadidByUri(String uri) throws MicroException {
if (UUIDUtils.isUuid(uri)) {
return uri;
}
if (!StringUtils.startsWith(uri, FileSystemConstant.FILE_NAMESPACE)) {
throw new IllegalArgumentException();
}
URI newUri = URI.create(uri);
if (null == newUri) {
throw new MicroException(CommonError.illegal_args, "无法识别的文件路径");
}
return newUri.getHost();
}
/**
* 获取文件超时时间
* expires:
* 0:表示永久
* 数字:具体超时天数
* null:跟随文件空间的超时时间
*
* @param fileSpace 文件空间
* @param expires 文件过期天数
* @param currentTime 当前时间
* @return java.util.Date
* @author wuzm
* @date 2020/7/13
*/
public static Date getExpireTime(FileSpace fileSpace, Integer expires, Date currentTime) {
Date expiresTime = null;
//文件时间处理
if (null == expires) {
Integer lifeCycle = fileSpace.getLifecycle();
if (null != lifeCycle && lifeCycle > 0) {
expiresTime = DateUtils.addDays(currentTime, lifeCycle);
}
} else if (expires > 0) {
expiresTime = DateUtils.addDays(currentTime, expires);
}
return expiresTime;
}
public static File inputstreamConverterFile(InputStream inputStream ,String sourceType) throws IOException {
String fileName = UUIDUtils.generate() + "." + sourceType;
//创建临时文件
File tempDirPath = new File(System.getProperty("java.io.tmpdir"));
fileName = FileUtil.changeFileNameToTargetSuffix(fileName, sourceType);
File tempFile = new File(tempDirPath, fileName);
//把输入流转换成和源文件格式相同的图片,存在临时文件中
int index;
byte[] bytes = new byte[1024];
FileOutputStream outputStream = new FileOutputStream(tempFile);
while ((index = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, index);
outputStream.flush();
}
outputStream.close();
return tempFile;
}
}MultipartFile拓展实体类
java
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
public class MockMultipartFile implements MultipartFile {
private final String name;
private String originalFilename;
@Nullable
private String contentType;
private final byte[] content;
/**
* Create a new MockMultipartFile with the given content.
* @param name the name of the file
* @param content the content of the file
*/
public MockMultipartFile(String name, @Nullable byte[] content) {
this(name, "", null, content);
}
/**
* Create a new MockMultipartFile with the given content.
* @param name the name of the file
* @param contentStream the content of the file as stream
* @throws IOException if reading from the stream failed
*/
public MockMultipartFile(String name, InputStream contentStream) throws IOException {
this(name, "", null, FileCopyUtils.copyToByteArray(contentStream));
}
/**
* Create a new MockMultipartFile with the given content.
* @param name the name of the file
* @param originalFilename the original filename (as on the client's machine)
* @param contentType the content type (if known)
* @param content the content of the file
*/
public MockMultipartFile(
String name, @Nullable String originalFilename, @Nullable String contentType, @Nullable byte[] content) {
Assert.hasLength(name, "Name must not be null");
this.name = name;
this.originalFilename = (originalFilename != null ? originalFilename : "");
this.contentType = contentType;
this.content = (content != null ? content : new byte[0]);
}
/**
* Create a new MockMultipartFile with the given content.
* @param name the name of the file
* @param originalFilename the original filename (as on the client's machine)
* @param contentType the content type (if known)
* @param contentStream the content of the file as stream
* @throws IOException if reading from the stream failed
*/
public MockMultipartFile(
String name, @Nullable String originalFilename, @Nullable String contentType, InputStream contentStream)
throws IOException {
this(name, originalFilename, contentType, FileCopyUtils.copyToByteArray(contentStream));
}
@Override
public String getName() {
return this.name;
}
@Override
public String getOriginalFilename() {
return this.originalFilename;
}
@Override
@Nullable
public String getContentType() {
return this.contentType;
}
@Override
public boolean isEmpty() {
return (this.content.length == 0);
}
@Override
public long getSize() {
return this.content.length;
}
@Override
public byte[] getBytes() throws IOException {
return this.content;
}
@Override
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(this.content);
}
@Override
public void transferTo(File dest) throws IOException, IllegalStateException {
FileCopyUtils.copy(this.content, dest);
}
}文件转换
文件转换支持word、pdf、html、txt等格式之间的相互转换
工具类
wordutil
java
import com.aspose.words.Document;
import com.aspose.words.License;
import com.aspose.words.SaveFormat;
import com.commnetsoft.commons.utils.StringUtils;
import com.commnetsoft.commons.utils.UUIDUtils;
import com.commnetsoft.file.converter.AbstractFileConverter;
import com.commnetsoft.file.utils.FileUtil;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.converter.WordToTextConverter;
import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
/**
* @ClassName WordUtil
* @Author wujs
* @Date 2020/9/25 11:15
* @Version 1.0
*/
public class WordUtil {
private final static Logger logger = LoggerFactory.getLogger(WordUtil.class);
/**
* 支持docy与docx互转,doc和docx转pdf
*
* @param inputStream
* @param type
* @return com.commnetsoft.commons.Result<java.io.File>
* @author wujs
* @date 2020/8/24 14:07
*/
public static File wordConvert(InputStream inputStream, String type) {
File tempDirPath = new File(System.getProperty("java.io.tmpdir"));
File pdffile = new File(tempDirPath, UUIDUtils.generate() + "." + type);
FileOutputStream fileOS = null;
// 验证License
if (!getLicense()) {
logger.error("验证License失败!");
return null;
}
try {
Document doc = new Document(inputStream);
fileOS = new FileOutputStream(pdffile);
// 保存转换的pdf文件
if (AbstractFileConver
ter.FILE_TYPE_PDF.equals(type)) {
doc.save(fileOS, SaveFormat.PDF);
} else if (AbstractFileConverter.FILE_TYPE_DOC.equals(type)) {
doc.save(fileOS, SaveFormat.DOC);
} else {
doc.save(fileOS, SaveFormat.DOCX);
}
return pdffile;
} catch (Exception e) {
logger.error("error:", e);
} finally {
try {
if (fileOS != null) {
fileOS.close();
}
} catch (IOException e) {
logger.error("error:", e);
}
}
return null;
}
public static boolean getLicense() {
boolean result = false;
try {
// 凭证
String licenseStr = "<License>\n" + " <Data>\n" + " <Products>\n"
+ " <Product>Aspose.Total for Java</Product>\n"
+ " <Product>Aspose.Words for Java</Product>\n" + " </Products>\n"
+ " <EditionType>Enterprise</EditionType>\n"
+ " <SubscriptionExpiry>20991231</SubscriptionExpiry>\n"
+ " <LicenseExpiry>20991231</LicenseExpiry>\n"
+ " <SerialNumber>8bfe198c-7f0c-4ef8-8ff0-acc3237bf0d7</SerialNumber>\n" + " </Data>\n"
+ " <Signature>sNLLKGMUdF0r8O1kKilWAGdgfs2BvJb/2Xp8p5iuDVfZXmhppo+d0Ran1P9TKdjV4ABwAgKXxJ3jcQTqE/2IRfqwnPf8itN8aFZlV3TJPYeD3yWE7IT55Gz6EijUpC7aKeoohTb4w2fpox58wWoF3SNp6sK6jDfiAUGEHYJ9pjU=</Signature>\n"
+ "</License>";
InputStream license = new ByteArrayInputStream(licenseStr.getBytes("UTF-8"));
License asposeLic = new License();
asposeLic.setLicense(license);
result = true;
} catch (Exception e) {
logger.error("error:", e);
}
return result;
}
/**
* word转txt
*
* @param inputStream
* @param targetFileType
* @return java.io.File
* @author wujs
* @date 2020/9/24 16:28
*/
public static File wordToTxt(InputStream inputStream, String targetFileType, String sourceType) throws IOException {
String text = null;
try {
if (StringUtils.equals(AbstractFileConverter.FILE_TYPE_DOCX, sourceType)) {
XWPFDocument document = new XWPFDocument(inputStream);
XWPFWordExtractor wordExtractor = new XWPFWordExtractor(document);
text = wordExtractor.getText();
if (null != document) {
document.close();
}
if (null != wordExtractor) {
wordExtractor.close();
}
}
if (StringUtils.equals(AbstractFileConverter.FILE_TYPE_DOC, sourceType)) {
HWPFDocument documentDoc = new HWPFDocument(inputStream);
StringBuilder sb = documentDoc.getText();
if (null != sb) {
text = sb.toString();
}
if (null != documentDoc) {
documentDoc.close();
}
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
File tempDirPath = new File(System.getProperty("java.io.tmpdir"));
File txtFile = new File(tempDirPath, UUIDUtils.generate() + "." + targetFileType);
if (StringUtils.isBlank(text)) {
return txtFile;
}
byte[] bytes = text.getBytes("UTF-8");
OutputStream os = new FileOutputStream(txtFile);
os.write(bytes);
if (os != null) {
os.flush();
os.close();
}
return txtFile;
}
/**
* txt文件转word文件
* @param inputStreamn
* @param type
* @return java.io.File
* @author lijx
* date 2020/8/28 10:33
*/
public static File txtToWordByType(InputStream inputStreamn, String type) throws IOException {
String fileName = UUIDUtils.generate();
File tempDirPath = new File(System.getProperty("java.io.tmpdir"));
File wordFile = new File(tempDirPath, FileUtil.changeFileNameToTargetSuffix(fileName, type));
FileOutputStream os = null;
try {
os = new FileOutputStream(wordFile);
XWPFDocument xwpfDocument = new XWPFDocument();
XWPFParagraph paragraph = xwpfDocument.createParagraph();
XWPFRun run = paragraph.createRun();
run.setText(readTxt(inputStreamn));
xwpfDocument.write(os);
xwpfDocument.close();
} finally {
if (os != null) {
os.flush();
os.close();
inputStreamn.close();
}
}
return wordFile;
}
/**
* 读取text文件的内容
* @param inputStream
* @return java.lang.String
* @author lijx
* date 2020/8/28 9:25
*/
public static String readTxt(InputStream inputStream) throws IOException {
StringBuilder builder = new StringBuilder();
String line; // 用来保存每行读取的内容
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
line = reader.readLine(); // 读取第一行
while (line != null) { // 如果 line 为空说明读完了
builder.append(line + "\r\n"); // 将读到的内容添加到 builder 中
line = reader.readLine(); // 读取下一行
}
reader.close();
inputStream.close();
return builder.toString();
}
/**
* 将doc文件转成txt文本文件
*
* @param inputStream
* @param targetType
* @return java.io.File
* @author wujs
* @date 2020/9/29 11:23
*/
public static File docToTxt(InputStream inputStream, String targetType) throws Exception {
WordToTextConverter converter = new WordToTextConverter(DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument());
HWPFDocument wordDocument = new HWPFDocument(inputStream);
converter.processDocument(wordDocument);
//对HWPFDocument进行转换
String fileName = UUIDUtils.generate();
File tempDirPath = new File(System.getProperty("java.io.tmpdir"));
File wordFile = new File(tempDirPath, FileUtil.changeFileNameToTargetSuffix(fileName, targetType));
Writer writer = new FileWriter(wordFile);
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.ENCODING, "utf-8");
//是否添加空格
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.METHOD, "text");
transformer.transform(
new DOMSource(converter.getDocument()),
new StreamResult(writer));
return wordFile;
}
/**将docx文件转成TXT文件
*
* @param inputStream
* @param targetType
* @return
* @throws Exception
*/
public static File docxToTxt(InputStream inputStream, String targetType) throws Exception {
//先把docx文件转成doc文件
File file = wordConvert(inputStream, AbstractFileConverter.FILE_TYPE_DOC);
FileInputStream fileInputStream = new FileInputStream(file);
File txtFile = docToTxt(fileInputStream, targetType);
return txtFile;
}
}Transform
java
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DataFormat;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.*;
import java.util.HashMap;
/**
* @ClassName Transform
* @Author wujs
* @Date 2020/9/29 17:52
* @Version 1.0
*/
public class Transform {
private int lastColumn = 0;
private HashMap<Integer, HSSFCellStyle> styleMap = new HashMap();
public void transformXSSF(XSSFWorkbook workbookOld, HSSFWorkbook workbookNew) {
HSSFSheet sheetNew;
XSSFSheet sheetOld;
workbookNew.setMissingCellPolicy(workbookOld.getMissingCellPolicy());
for (int i = 0; i < workbookOld.getNumberOfSheets(); i++) {
sheetOld = workbookOld.getSheetAt(i);
sheetNew = workbookNew.getSheet(sheetOld.getSheetName());
sheetNew = workbookNew.createSheet(sheetOld.getSheetName());
this.transform(workbookOld, workbookNew, sheetOld, sheetNew);
}
}
private void transform(XSSFWorkbook workbookOld, HSSFWorkbook workbookNew,
XSSFSheet sheetOld, HSSFSheet sheetNew) {
sheetNew.setDisplayFormulas(sheetOld.isDisplayFormulas());
sheetNew.setDisplayGridlines(sheetOld.isDisplayGridlines());
sheetNew.setDisplayGuts(sheetOld.getDisplayGuts());
sheetNew.setDisplayRowColHeadings(sheetOld.isDisplayRowColHeadings());
sheetNew.setDisplayZeros(sheetOld.isDisplayZeros());
sheetNew.setFitToPage(sheetOld.getFitToPage());
sheetNew.setHorizontallyCenter(sheetOld.getHorizontallyCenter());
sheetNew.setMargin(Sheet.BottomMargin,
sheetOld.getMargin(Sheet.BottomMargin));
sheetNew.setMargin(Sheet.FooterMargin,
sheetOld.getMargin(Sheet.FooterMargin));
sheetNew.setMargin(Sheet.HeaderMargin,
sheetOld.getMargin(Sheet.HeaderMargin));
sheetNew.setMargin(Sheet.LeftMargin,
sheetOld.getMargin(Sheet.LeftMargin));
sheetNew.setMargin(Sheet.RightMargin,
sheetOld.getMargin(Sheet.RightMargin));
sheetNew.setMargin(Sheet.TopMargin, sheetOld.getMargin(Sheet.TopMargin));
sheetNew.setPrintGridlines(sheetNew.isPrintGridlines());
sheetNew.setRightToLeft(sheetNew.isRightToLeft());
sheetNew.setRowSumsBelow(sheetNew.getRowSumsBelow());
sheetNew.setRowSumsRight(sheetNew.getRowSumsRight());
sheetNew.setVerticallyCenter(sheetOld.getVerticallyCenter());
HSSFRow rowNew;
for (Row row : sheetOld) {
rowNew = sheetNew.createRow(row.getRowNum());
if (rowNew != null)
this.transform(workbookOld, workbookNew, (XSSFRow) row, rowNew);
}
for (int i = 0; i < this.lastColumn; i++) {
sheetNew.setColumnWidth(i, sheetOld.getColumnWidth(i));
sheetNew.setColumnHidden(i, sheetOld.isColumnHidden(i));
}
for (int i = 0; i < sheetOld.getNumMergedRegions(); i++) {
CellRangeAddress merged = sheetOld.getMergedRegion(i);
sheetNew.addMergedRegion(merged);
}
}
private void transform(XSSFWorkbook workbookOld, HSSFWorkbook workbookNew,
XSSFRow rowOld, HSSFRow rowNew) {
HSSFCell cellNew;
rowNew.setHeight(rowOld.getHeight());
for (Cell cell : rowOld) {
cellNew = rowNew.createCell(cell.getColumnIndex(),
cell.getCellType());
if (cellNew != null)
this.transform(workbookOld, workbookNew, (XSSFCell) cell,
cellNew);
}
this.lastColumn = Math.max(this.lastColumn, rowOld.getLastCellNum());
}
private void transform(XSSFWorkbook workbookOld, HSSFWorkbook workbookNew,
XSSFCell cellOld, HSSFCell cellNew) {
cellNew.setCellComment(cellOld.getCellComment());
Integer hash = cellOld.getCellStyle().hashCode();
if (this.styleMap != null && !this.styleMap.containsKey(hash)) {
this.transform(workbookOld, workbookNew, hash,
cellOld.getCellStyle(),
(HSSFCellStyle) workbookNew.createCellStyle());
}
cellNew.setCellStyle(this.styleMap.get(hash));
switch (cellOld.getCellType()) {
case BLANK:
break;
case BOOLEAN:
cellNew.setCellValue(cellOld.getBooleanCellValue());
break;
case ERROR:
cellNew.setCellValue(cellOld.getErrorCellValue());
break;
case FORMULA:
cellNew.setCellValue(cellOld.getCellFormula());
break;
case NUMERIC:
cellNew.setCellValue(cellOld.getNumericCellValue());
break;
case STRING:
cellNew.setCellValue(cellOld.getStringCellValue());
break;
default:
System.out.println("transform: Unbekannter Zellentyp "
+ cellOld.getCellType());
}
}
private void transform(XSSFWorkbook workbookOld, HSSFWorkbook workbookNew,
Integer hash, XSSFCellStyle styleOld, HSSFCellStyle styleNew) {
styleNew.setAlignment(styleOld.getAlignment());
styleNew.setBorderBottom(styleOld.getBorderBottom());
styleNew.setBorderLeft(styleOld.getBorderLeft());
styleNew.setBorderRight(styleOld.getBorderRight());
styleNew.setBorderTop(styleOld.getBorderTop());
styleNew.setDataFormat(this.transform(workbookOld, workbookNew,
styleOld.getDataFormat()));
styleNew.setFillBackgroundColor(styleOld.getFillBackgroundColor());
styleNew.setFillForegroundColor(styleOld.getFillForegroundColor());
styleNew.setFillPattern(styleOld.getFillPattern());
styleNew.setFont(this.transform(workbookNew,
(XSSFFont) styleOld.getFont()));
styleNew.setHidden(styleOld.getHidden());
styleNew.setIndention(styleOld.getIndention());
styleNew.setLocked(styleOld.getLocked());
styleNew.setVerticalAlignment(styleOld.getVerticalAlignment());
styleNew.setWrapText(styleOld.getWrapText());
this.styleMap.put(hash, styleNew);
}
private short transform(XSSFWorkbook workbookOld, HSSFWorkbook workbookNew,
short index) {
DataFormat formatOld = workbookOld.createDataFormat();
DataFormat formatNew = workbookNew.createDataFormat();
return formatNew.getFormat(formatOld.getFormat(index));
}
private HSSFFont transform(HSSFWorkbook workbookNew, XSSFFont fontOld) {
HSSFFont fontNew = workbookNew.createFont();
fontNew.setBold(true);
fontNew.setCharSet(fontOld.getCharSet());
fontNew.setColor(fontOld.getColor());
fontNew.setFontName(fontOld.getFontName());
fontNew.setFontHeight(fontOld.getFontHeight());
fontNew.setItalic(fontOld.getItalic());
fontNew.setStrikeout(fontOld.getStrikeout());
fontNew.setTypeOffset(fontOld.getTypeOffset());
fontNew.setUnderline(fontOld.getUnderline());
return fontNew;
}
}PictureUtil
java
import com.aspose.words.Document;
import com.aspose.words.ImageSaveOptions;
import com.aspose.words.SaveFormat;
import com.commnetsoft.commons.utils.StringUtils;
import com.commnetsoft.commons.utils.UUIDUtils;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.exception.MicroRuntimeException;
import com.commnetsoft.file.converter.AbstractFileConverter;
import com.commnetsoft.file.utils.FileUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipOutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
/**
* @className: PictureUtil
* @author: lijx
* @date: 2020/8/21 14:54
* @version: 1.0
*/
public class PictureUtil {
private static final Logger log = LoggerFactory.getLogger(PictureUtil.class);
public static final String FILE_TYPE_ZIP = "zip";
/**
* jpg、jpeg、png格式互转
*
* @param inputStream
* @param targetType
* @param sourceType
* @return java.io.File
* @author wujs
* @date 2020/9/27 9:54
*/
public static File pictureConvertByType(InputStream inputStream, String targetType, String sourceType) throws IOException {
//把inputstream转换成file存在临时目录中
File pictureFile = FileUtil.inputstreamConverterFile(inputStream, sourceType);
//创建按目标格式转换成功后文件存储的目录
File catalog = new File(System.getProperty("java.io.tmpdir"));
File tempFile = new File(catalog, UUIDUtils.generate() + "." + targetType);
OutputStream outputStream = new FileOutputStream(tempFile);
BufferedImage bufferedImage = ImageIO.read(pictureFile);
BufferedImage newBufferedImage = new BufferedImage(bufferedImage.getWidth(), bufferedImage.getHeight(), BufferedImage.TYPE_INT_RGB);
newBufferedImage.createGraphics().drawImage(bufferedImage, 0, 0, Color.WHITE, null);
ImageIO.write(newBufferedImage, targetType, tempFile);
if (null != bufferedImage) bufferedImage.flush();
if (null != newBufferedImage) newBufferedImage.flush();
inputStream.close();
outputStream.flush();
outputStream.close();
//删除原文件
pictureFile.delete();
return tempFile;
}
/**
* 将pdf转换成图片,如果不超出10张,会将图片拼成长图,如果超过10张,转成zip压缩包返回
* @param inputStream
* @param type
* @return java.io.File
* @author lijx
* date 2020/8/25 15:02
*/
public static File pdfToPictureByType(InputStream inputStream, String type) throws IOException {
File tempDirPath = new File(System.getProperty("java.io.tmpdir"));
PDDocument pdDocument = PDDocument.load(inputStream);
try {
PDFRenderer renderer = new PDFRenderer(pdDocument);
int pages = pdDocument.getNumberOfPages();
if (pages < 1) {
throw new MicroRuntimeException(CommonError.forbidden, "未找到pdf的内容");
}
if (StringUtils.startsWith(type, ".")) {
type = StringUtils.substringAfter(type, ".");
}
List<File> files = new ArrayList<>();
BufferedImage image = null;
String fileName = UUIDUtils.generate();
for (int i = 0; i < pages; i++) {
File tempFile = new File(tempDirPath, fileName + i + "." + type);
image = renderer.renderImageWithDPI(i, 144);
if (null != image) {
ImageIO.write(image, type, tempFile);
files.add(tempFile);
}
}
if (null != image) image.flush();
return returnFile(files, tempDirPath, fileName, type);
} finally {
pdDocument.close();
}
}
private static File returnFile(List<File> files, File tempDirPath, String fileName, String type) throws IOException {
try {
if (CollectionUtils.isEmpty(files)) {
throw new MicroRuntimeException(CommonError.forbidden, "未找到转换后的图片信息");
}
File resultFile = null;
if (files.size() > 10) {
resultFile = packgePicture(tempDirPath, files, FileUtil.changeFileNameToTargetSuffix(fileName, AbstractFileConverter.FILE_TYPE_ZIP));
} else {
File changeFile = mergePicture(files, type);
resultFile = new File(tempDirPath.getPath() + "/" + FileUtil.changeFileNameToTargetSuffix(fileName, type));
FileUtils.copyFile(changeFile, resultFile);
if (changeFile.exists()) {
changeFile.delete();
}
}
return resultFile;
} finally {
files.parallelStream().filter(chunkFile -> chunkFile.exists()).forEach(File::delete);
}
}
/**
* 将多张图片合成长图
* @param files
* @param suffix
* @return java.io.File
* @author lijx
* date 2020/8/25 15:06
*/
public static File mergePicture(List<File> files, String suffix) throws IOException {
if (files.size() == 1) {
return files.get(0);
}
if (StringUtils.startsWith(suffix, ".")) {
suffix = StringUtils.substringAfter(suffix, ".");
}
File tempFile = null;
for (int i = 1; i < files.size(); i++) {
if (i == 1) {
tempFile = iterableMergePicture(files.get(0), files.get(1), suffix);
} else {
tempFile = iterableMergePicture(tempFile, files.get(i), suffix);
}
}
return tempFile;
}
/**
* 迭代合成图片
* @param upFile
* @param downFile
* @param suffix
* @return java.io.File
* @author lijx
* date 2020/8/25 15:06
*/
private static File iterableMergePicture(File upFile, File downFile, String suffix) throws IOException {
if (null == upFile || !upFile.exists()) {
return downFile;
}
if (null == downFile || !downFile.exists()) {
return upFile;
}
List<File> files = new ArrayList<>();
files.add(upFile);
files.add(downFile);
Integer allWidth = 0; // 图片总宽度
Integer allHeight = 0; // 图片总高度
List<BufferedImage> imgs = new ArrayList<>();
BufferedImage read = null;
for (int i = 0; i < files.size(); i++) {
read = ImageIO.read(files.get(i));
if (null != read) {
imgs.add(read);
//竖向
if (i == 0) {
allWidth = imgs.get(0).getWidth();
}
allHeight += imgs.get(i).getHeight();
}
}
if (null != read) {
read.getGraphics().dispose();
read.flush();
}
BufferedImage combined = new BufferedImage(allWidth, allHeight, BufferedImage.TYPE_INT_RGB);
Graphics g = combined.getGraphics();
// 竖向合成
Integer height = 0;
for (int i = 0; i < imgs.size(); i++) {
g.drawImage(imgs.get(i), 0, height, null);
height += imgs.get(i).getHeight();
}
if (combined != null && upFile != null) {
ImageIO.write(combined, suffix, upFile);
}
g.dispose();
combined.flush();
return upFile;
}
/**
* 将文件打包成一个zip文件
* @param tempDirPath
* @param files
* @param packgeName
* @return java.io.File
* @author lijx
* date 2020/8/25 15:06
*/
public static File packgePicture(File tempDirPath, List<File> files, String packgeName) throws IOException {
File tempZip = new File(tempDirPath, packgeName);
FileOutputStream outputStream = null;
BufferedOutputStream bufferedOutputStream = null;
ZipOutputStream zipOutputStream = null;
BufferedInputStream bufferedInputStream = null;
InputStream input = null;
int length;
byte[] readByte = new byte[1024];
try {
outputStream = new FileOutputStream(tempZip);
bufferedOutputStream = new BufferedOutputStream(outputStream);
zipOutputStream = new ZipOutputStream(outputStream);
zipOutputStream.setEncoding("GBK");
for (int i = 0; i < files.size(); i++) {
input = new FileInputStream(files.get(i));
bufferedInputStream = new BufferedInputStream(input);
zipOutputStream.putNextEntry(new ZipEntry(files.get(i).getName()));
while ((length = bufferedInputStream.read(readByte)) > 0) {
zipOutputStream.write(readByte, 0, length);
}
bufferedInputStream.close();
}
} finally {
if (null != zipOutputStream) zipOutputStream.closeEntry();
if (null != zipOutputStream) zipOutputStream.close();
if (null != bufferedOutputStream) bufferedOutputStream.close();
if (null != outputStream) outputStream.close();
if (null != bufferedInputStream) bufferedInputStream.close();
if (null != input) input.close();
}
return tempZip;
}
/**
* word文件转图片,如果不超出10张,会将图片拼成长图,如果超过10张,转成zip压缩包返回
* @param inputStream
* @param type
* @return java.io.File
* @author lijx
* date 2020/8/25 16:50
*/
public static File wordToPictureByType(InputStream inputStream, String type) {
try {
Document document = new Document(inputStream);
ImageSaveOptions options = new ImageSaveOptions(SaveFormat.PNG);
int pageCount = document.getPageCount();
File tempDirPath = new File(System.getProperty("java.io.tmpdir"));
String fileName = UUIDUtils.generate();
List<File> files = new ArrayList<>();
for (int i = 0; i < pageCount; i++) {
File tempFile = new File(tempDirPath, fileName + i + "." + type);
FileOutputStream os = new FileOutputStream(tempFile);
options.setPageIndex(i);
document.save(os, options);
files.add(tempFile);
if (os != null) os.close();
}
return returnFile(files, tempDirPath, fileName, type);
} catch (Exception e) {
log.error("word转图片失败", e);
throw new MicroRuntimeException(CommonError.forbidden, "word转图片失败");
}
}
/**
* 图片转pdf
* @param inputStream
* @return java.io.File
* @author lijx
* date 2020/8/27 11:29
*/
public static File pictureToPdf(InputStream inputStream, String type) throws IOException {
String fileName = UUIDUtils.generate();
PDDocument document = new PDDocument();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
byte[] buffBytes = new byte[1024];
int read = 0;
while ((read = inputStream.read(buffBytes)) != -1) {
stream.write(buffBytes, 0, read);
}
PDImageXObject fromByteArray = PDImageXObject.createFromByteArray(document, stream.toByteArray(), fileName);
float height = fromByteArray.getHeight();
float width = fromByteArray.getWidth();
float x = 0;
float y = 0;
PDRectangle a4 = PDRectangle.A4;
if (height < a4.getHeight()) {
y = a4.getHeight() - height;
height = a4.getHeight();
}
if (width < a4.getWidth()) {
width = a4.getWidth();
}
PDRectangle pdRectangle = new PDRectangle(width, height);
PDPage page = new PDPage(pdRectangle);
document.addPage(page);
PDPageContentStream contentStream = new PDPageContentStream(document, page);
contentStream.drawImage(fromByteArray, x, y);
contentStream.close();
File tempDirPath = new File(System.getProperty("java.io.tmpdir"));
File tempFile = new File(tempDirPath, UUIDUtils.generate() + "." + type);
document.save(tempFile);
document.close();
return tempFile;
}
}PdfUtil
java
import com.aspose.pdf.Document;
import com.aspose.pdf.License;
import com.aspose.pdf.SaveFormat;
import com.commnetsoft.commons.utils.StringUtils;
import com.commnetsoft.commons.utils.UUIDUtils;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.exception.MicroException;
import com.commnetsoft.exception.MicroRuntimeException;
import com.commnetsoft.file.converter.AbstractFileConverter;
import com.commnetsoft.file.converter.util.docxconverter.DocxHelper;
import org.docx4j.openpackaging.exceptions.Docx4JException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.xml.bind.JAXBException;
import java.io.*;
/**
* @ClassName PdfUtil
* @Author wujs
* @Date 2020/9/24 15:53
* @Version 1.0
*/
@Component
public class PdfUtil {
private final static Logger logger = LoggerFactory.getLogger(PdfUtil.class);
@Autowired
private PDFHelper pdfHelper;
@Autowired
private DocxHelper docxHelper;
public static File pdfToWord(InputStream inputStream, String targetFileType) throws IOException {
if (!getLicense()) {
logger.error("验签失败!");
return null;
}
FileOutputStream os = null;
try {
File catalog = new File(System.getProperty("java.io.tmpdir"));
String filePath = catalog + "\\" + UUIDUtils.generate() + "." + targetFileType;
Document pdfDocument = new Document(inputStream);
os = new FileOutputStream(filePath);
if (StringUtils.equals(AbstractFileConverter.FILE_TYPE_DOC, targetFileType)) {
pdfDocument.save(os, SaveFormat.Doc);
} else {
pdfDocument.save(os, SaveFormat.DocX);
}
File file = new File(filePath);
return file;
} catch (Exception e) {
logger.error("转换失败!", e);
} finally {
inputStream.close();
if (null != os) {
os.close();
}
}
return null;
}
public static File txtToPdf(InputStream inputStream, String targetType) throws IOException {
//// Document document = new Document();
//// //创建存储pdf的临时文件
//// File catalog = new File(System.getProperty("java.io.tmpdir"));
//// String filePath = catalog + "\\" + UUIDUtils.generate() + "." + targetType;
//// OutputStream outputStream = new FileOutputStream(new File(filePath));
//// PdfWriter.getInstance(document, outputStream);
//// document.open();
//// //方法一:使用Windows系统字体(TrueType)
//// //字体设置
//// BaseFont bf = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
////
//// //创建Font对象,将基础字体对象,字体大小,字体风格
//// Font font = new Font(bf, 13, Font.NORMAL);
//// InputStreamReader isr = new InputStreamReader((inputStream), "UTF-8");
//// BufferedReader bufferedReader = new BufferedReader(isr);
//// String str = "";
//// while ((str = bufferedReader.readLine()) != null) {
//// document.add(new Paragraph(str, font));
//// }
//// document.close();
//// inputStream.close();
//// outputStream.close();
//// File tempFile = new File(filePath);
//
// return tempFile;
throw new MicroRuntimeException(CommonError.unimplement);
}
private static boolean getLicense() {
boolean result = false;
try {
// 凭证
String licenseStr = "<License>\n" + " <Data>\n" + " <Products>\n"
+ " <Product>Aspose.Total for Java</Product>\n"
+ " <Product>Aspose.Pdf for Java</Product>\n"
+ " </Products>\n"
+ " <EditionType>Enterprise</EditionType>\n"
+ " <SubscriptionExpiry>29991231</SubscriptionExpiry>\n"
+ " <LicenseExpiry>29991231</LicenseExpiry>\n"
+ " <SerialNumber>8bfe198c-7f0c-4ef8-8ff0-acc3237bf0d7</SerialNumber>\n" + " </Data>\n"
+ " <Signature>sNLLKGMUdF0r8O1kKilWAGdgfs2BvJb/2Xp8p5iuDVfZXmhppo+d0Ran1P9TKdjV4ABwAgKXxJ3jcQTqE/2IRfqwnPf8itN8aFZlV3TJPYeD3yWE7IT55Gz6EijUpC7aKeoohTb4w2fpox58wWoF3SNp6sK6jDfiAUGEHYJ9pjU=</Signature>\n"
+ "</License>";
InputStream license = new ByteArrayInputStream(licenseStr.getBytes("UTF-8"));
License asposeLic = new License();
asposeLic.setLicense(license);
result = true;
} catch (Exception e) {
logger.error("error:", e);
}
return result;
}
public static String getHtmlString(InputStream inputStream) {
String htmlString = "";
InputStreamReader read = null;
BufferedReader reader = null;
try {
read = new InputStreamReader(inputStream, "UTF-8");
reader = new BufferedReader(read);
String line;
while ((line = reader.readLine()) != null) {
htmlString += line;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != read) {
try {
read.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (null != reader) {
try {
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
return htmlString;
}
public File convert(InputStream inputStream, String targetFileType) throws IOException, MicroException, JAXBException, Docx4JException {
String htmlString = getHtmlString(inputStream);
File catalog = new File(System.getProperty("java.io.tmpdir"));
String filePath = catalog + "\\" + UUIDUtils.generate() + "." + targetFileType;
FileOutputStream outputStream = new FileOutputStream(filePath);
if (StringUtils.equals(targetFileType, "docx")) {
docxHelper.convert(htmlString, null, false, null, outputStream);
}
if (StringUtils.equals(targetFileType, "pdf")) {
pdfHelper.convert(htmlString, null, false, null, outputStream);
}
File file = new File(filePath);
return file;
}
}PDFHelper
java
import com.commnetsoft.commons.utils.StringUtils;
import com.commnetsoft.commons.utils.UUIDUtils;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.exception.MicroException;
import com.commnetsoft.exception.MicroRuntimeException;
import com.commnetsoft.file.model.HtmlSheetDto;
import com.itextpdf.forms.PdfPageFormCopier;
import com.itextpdf.html2pdf.ConverterProperties;
import com.itextpdf.html2pdf.HtmlConverter;
import com.itextpdf.io.codec.Base64;
import com.itextpdf.io.font.PdfEncodings;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.events.Event;
import com.itextpdf.kernel.events.IEventHandler;
import com.itextpdf.kernel.events.PdfDocumentEvent;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.*;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.kernel.pdf.canvas.draw.DottedLine;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.*;
import com.itextpdf.layout.font.FontProvider;
import com.itextpdf.layout.property.*;
import org.apache.commons.lang3.BooleanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* PDF转换工具类
* @author sunwen
* @since 2019/12/13
*/
@Component
@RefreshScope
public class PDFHelper {
private static final Logger log = LoggerFactory.getLogger(PDFHelper.class);
@Value("#{fileConfig.fontsPath}")
private String fontsPath;
private static Map<String, PageSize> pagerMap = new HashMap<>();
static {
pagerMap.put("A0", PageSize.A0);
pagerMap.put("A1", PageSize.A1);
pagerMap.put("A2", PageSize.A2);
pagerMap.put("A3", PageSize.A3);
pagerMap.put("A4", PageSize.A4);
pagerMap.put("A5", PageSize.A5);
pagerMap.put("A6", PageSize.A6);
pagerMap.put("A7", PageSize.A7);
pagerMap.put("A8", PageSize.A8);
pagerMap.put("A9", PageSize.A9);
pagerMap.put("A10", PageSize.A10);
pagerMap.put("B0", PageSize.B0);
pagerMap.put("B1", PageSize.B1);
pagerMap.put("B2", PageSize.B2);
pagerMap.put("B3", PageSize.B3);
pagerMap.put("B4", PageSize.B4);
pagerMap.put("B5", PageSize.B5);
pagerMap.put("B6", PageSize.B6);
pagerMap.put("B7", PageSize.B7);
pagerMap.put("B8", PageSize.B8);
pagerMap.put("B9", PageSize.B9);
pagerMap.put("B10", PageSize.B10);
}
private ConverterProperties converterProperties;
private ConverterProperties getConverterProperties(){
if(converterProperties == null){
converterProperties = new ConverterProperties();
FontProvider fontProvider = new FontProvider();
fontProvider.addStandardPdfFonts();
fontProvider.addDirectory(fontsPath);
// fontProvider.addFont(fontsPath + "/SIMSUN.TTF");//宋体
// fontProvider.addFont(fontsPath + "/SIMKAI.TTF");//楷体
// fontProvider.addFont(fontsPath + "/SIMHEI.TTF");//黑体
converterProperties.setFontProvider(fontProvider);
converterProperties.setCharset("UTF-8");
}
return converterProperties;
}
/**
* 创建文档
* @author sunwen
* @since 2020/12/10
*/
private static Document createDocumnet(PdfWriter pdfWriter, String pageSize, boolean rotate, Integer[] margins) throws MicroException {
DocumentProperties properties = new DocumentProperties();
PdfDocument pdfDocument = new PdfDocument(pdfWriter, properties);
PageSize ps;
if(StringUtils.isEmpty(pageSize)){
ps = PageSize.Default;
}else{
ps = pagerMap.get(pageSize);
if(ps == null){//TODO 支持 200X300的格式自定义页面大小
throw new MicroException(CommonError.illegal_args, "不支持的页面大小:"+ pageSize);
}
}
if(rotate){
ps = ps.rotate();
}
pdfDocument.setDefaultPageSize(ps);
Document document = new Document(pdfDocument);
float defaultMargin = 60 * 72 / 96f;
float[] ms = new float[]{defaultMargin, defaultMargin, defaultMargin, defaultMargin};
if(margins != null){
for(int i = 0; i < margins.length && i < ms.length; i++){
Integer m = margins[i];
if(m != null && m >= 0){
ms[i] = m * 72 / 96f;
}
}
}
document.setMargins(ms[0], ms[1], ms[2], ms[3]);
return document;
}
/**
* 将一个html转换成pdf文件
* @author sunwen
* @since 2019/12/25
*/
public void convert(String html, String pageSize, boolean rotate, Integer[] margins, OutputStream out) throws IOException, MicroException {
try (Document document = createDocumnet(new PdfWriter(out), pageSize, rotate, margins)) {
List<IElement> list = HtmlConverter.convertToElements(html, getConverterProperties());
for (IElement ie : list) {
setTable(ie);
IBlockElement element = (IBlockElement) ie;
element.setProperty(Property.SPLIT_CHARACTERS, ChineseSplitCharaters.instance);
document.add(element);
}
}
}
/**
* 将多个html转换成pdf文件
* @param sheet 页面
* @author sunwen
* @since 2019/12/25
*/
public void convert(HtmlSheetDto sheet, OutputStream out) throws IOException, MicroException {
try (Document document = createDocumnet(
new PdfWriter(out),
sheet.getPagesize(),
sheet.isRotate(),
sheet.getMargins()
)) {
PdfFont font = PdfFontFactory.createFont(fontsPath + "/SIMSUN.TTF", PdfEncodings.IDENTITY_H, true);
PdfFont titlefont = PdfFontFactory.createFont(fontsPath + "/SIMHEI.TTF", PdfEncodings.IDENTITY_H,true);
PageIndexEvent event = new PageIndexEvent(font);
document.getPdfDocument().addEventHandler(PdfDocumentEvent.END_PAGE, event);
addSheet(document, getConverterProperties(), titlefont, sheet, null, true);
}
}
/**
* 将多个html转换成带封面及目录的pdf文件
* @param book 根节点的html:封面 (封面如果超过一页将不显示) 为空不设置封面;children:内容页列表
* @param autOrdinal 目录是否需要自动编号
* @author sunwen
* @since 2019/12/25
*/
public void convertBook(HtmlSheetDto book, boolean autOrdinal, OutputStream out) throws IOException, MicroException {
//先转内容获取页码
File contentFile = new File(System.getProperty("java.io.tmpdir"), UUIDUtils.generate() + ".cont");
long t = System.currentTimeMillis();
Document contentDoc = createDocumnet(new PdfWriter(contentFile), book.getPagesize(), book.isRotate(), book.getMargins());
PdfFont font = PdfFontFactory.createFont(fontsPath + "/SIMSUN.TTF", PdfEncodings.IDENTITY_H,true);
List<Catalog> catalogs = new ArrayList<>();
try {
PageIndexEvent event = new PageIndexEvent(font);
contentDoc.getPdfDocument().addEventHandler(PdfDocumentEvent.END_PAGE, event);
boolean isBlank = true;
List<HtmlSheetDto> contentSheets = book.getChildren();
for(HtmlSheetDto item : contentSheets){
Catalog catalog = new Catalog();
isBlank = addSheet(contentDoc, getConverterProperties(), font, item, catalog, isBlank);
catalogs.add(catalog);
}
}finally {
try {
contentDoc.close();
}catch (Exception e){
//Empty
}
}
long t1 = System.currentTimeMillis();
Document document = createDocumnet(new PdfWriter(out), book.getPagesize(), book.isRotate(), book.getMargins());
try {
//添加目录
PdfFont titlefont = PdfFontFactory.createFont(fontsPath + "/SIMHEI.TTF", PdfEncodings.IDENTITY_H,true);
document.add(new Paragraph("目录").setFont(titlefont).setTextAlignment(TextAlignment.CENTER).setFontSize(18));
String ordinal = autOrdinal ? "" : null;
addCatalog(document, catalogs, ordinal,0, titlefont);
//添加封面(先添加封面移除多余页页后添加内容会NPE)
PdfDocument pdfDoc = document.getPdfDocument();
if (StringUtils.isNotEmpty(book.getHtml())) {
int end = pdfDoc.getNumberOfPages();
document.add(new AreaBreak(AreaBreakType.NEXT_PAGE));
List<IElement> list = HtmlConverter.convertToElements(book.getHtml(), converterProperties);
for (IElement ie : list) {
setTable(ie);
IBlockElement element = (IBlockElement) ie;
element.setProperty(Property.SPLIT_CHARACTERS, ChineseSplitCharaters.instance);
document.add(element);
}
int n = pdfDoc.getNumberOfPages();//封面移前
for (int i = n; i > end; i--) {
if (i == end + 1) {
pdfDoc.movePage(i, 1);
} else {
pdfDoc.removePage(i);
}
}
}
long t2 = System.currentTimeMillis();
PdfDocument content = new PdfDocument(new PdfReader(contentFile));
content.copyPagesTo(1, content.getNumberOfPages(), pdfDoc, new PdfPageFormCopier());
content.close();
contentFile.delete();
long t3 = System.currentTimeMillis();
log.info("PDF转换耗时{}ms,其中生成内容{}ms,生成封面及目录{}ms,拷贝内容{}ms", t3 - t, t1 - t, t2 - t1, t3 - t2);
}finally {
try {
document.close();
}catch (Exception e){
//Empty
}
}
}
/**
* @param catalog 目录列表
* @param isBlank 当前是否在一个空白页上
* @author sunwen
* @since 2020/12/10
*/
private static boolean addSheet(Document document, ConverterProperties properties, PdfFont font,
HtmlSheetDto sheet, Catalog catalog, boolean isBlank) throws IOException {
if(!isBlank && BooleanUtils.isTrue(sheet.getNewpage())){ //当前不在新页面 设置了分页,插入分页符
document.add(new AreaBreak());
isBlank = true;
}
int pageNum = document.getPdfDocument().getNumberOfPages();//FIXME sunwen 当前页写不下时换页,页码可能不准确
String image = sheet.getImage();
if(catalog != null && StringUtils.isEmpty(image)){//图片存在该页视为内容,不设置目录标题
catalog.setTitle(sheet.getTitle());
catalog.setPageNum(Math.max(1, pageNum));
}
boolean showTitle = BooleanUtils.isTrue(sheet.getShowtitle());
if(StringUtils.isNotEmpty(image)){
isBlank = false;
String[] strParts = image.split(",");
if(strParts.length == 2 && ("data:image/gif;base64".equals(strParts[0])
|| "data:image/png;base64".equals(strParts[0]) || "data:image/jpeg;base64".equals(strParts[0]))){
float titleHeight = 0f;
// log.error(document.getRenderer().getCurrentArea().getBBox().toString());
if(showTitle && StringUtils.isNotEmpty(sheet.getTitle())){
Paragraph title = new Paragraph(sheet.getTitle()).setFont(font);
title.setTextAlignment(TextAlignment.CENTER).setFontSize(16);
title.setKeepWithNext(true);//标题和图片不分页,
document.add(title);
titleHeight = 33.894f;//FIXME sunwen 设置keep后,标题占用高度需后面添加元素后才计算,无法动态获取标题高度
}
Image img = new Image(ImageDataFactory.create(Base64.decode(strParts[1])));
Rectangle areaRect = document.getRenderer().getCurrentArea().getBBox();
Rectangle imgRect = fitImage(areaRect.getWidth(), areaRect.getHeight() - titleHeight,
img.getImageWidth(), img.getImageHeight());
if(imgRect != null){
img.setAutoScale(true);
img.setMarginLeft(imgRect.getLeft()); //设置边距为了图片居中显示
img.setMarginRight(areaRect.getWidth() - imgRect.getRight());
}else{
img.setAutoScaleWidth(true);
}
document.add(img);
showTitle = false;//图片存在 标题视为图片标题,后面不设置文档标题
}else{
throw new MicroRuntimeException(CommonError.illegal_args, "不支持的图片格式");
}
}
if(showTitle && StringUtils.isNotEmpty(sheet.getTitle())){
//处理标题 样式
Paragraph title = new Paragraph(sheet.getTitle()).setFont(font);
title.setFontSize(16);//TODO 判断目录层级设置不同的字体大小
document.add(title);
}
if(StringUtils.isNotEmpty(sheet.getHtml())){//允许页面内容为空(只有标题)
isBlank = false;
List<IElement> list = HtmlConverter.convertToElements(sheet.getHtml(), properties);
for (IElement ie : list) {
setTable(ie);
// if(ie instanceof Paragraph){//FIXME sunwen 文本两端对齐无效
// ((Paragraph) ie).setTextAlignment(TextAlignment.JUSTIFIED);
// }
IBlockElement element = (IBlockElement) ie;
element.setProperty(Property.SPLIT_CHARACTERS, ChineseSplitCharaters.instance);
document.add(element);
}
}
if(sheet.getChildren() != null){
for(HtmlSheetDto item : sheet.getChildren()){
Catalog cc = catalog != null ? catalog.nextCatalog() : null;
isBlank = addSheet(document, properties, font, item, cc, isBlank);
}
}
return isBlank;
}
/**
* 计算图片是否可以放入容器
* 如果可以放入返回 图片区域否则返回null
* @author sunwen
* @since 2020/12/22
*/
private static Rectangle fitImage(float containerWidth, float containerHeight, float imageWidth, float imageHeight){
float minHeight = 150f;
float widthScale = containerWidth/imageWidth;
float height = imageHeight*widthScale;
if(height > minHeight && containerHeight < minHeight){//图片缩放后高度大于150 容器高度不足150时不允许放入容器
return null;
}
if(height > containerHeight){//宽度适配容器后,高度超过容器,按容器高度适配
float heightScale = containerHeight/imageHeight;
float width = imageWidth * heightScale;
float margin = (containerWidth - width)/2f;
return new Rectangle(margin, 0, width, containerHeight);
}else{
return new Rectangle(containerWidth, containerHeight);
}
}
/**
* 递归添加目录
* @param parentOrdinal 父级序号 传null表示不需要生成序号
* @author sunwen
* @since 2019/12/24
*/
private static void addCatalog(Document document, List<Catalog> catalogs, String parentOrdinal, int deep, PdfFont font){
if(catalogs == null){
return;
}
int i = 0;
for(Catalog catalog : catalogs) {
String index = parentOrdinal;
String title = catalog.getTitle();
int _deep = deep;
if(StringUtils.isNotEmpty(title)) {//标题存在才加入目录
if(parentOrdinal != null){
index = parentOrdinal + ++i + '.';
title = index + title;
}
Paragraph p = new Paragraph(title).setFont(font).setFontSize(12).setMarginLeft(12 * deep);
PdfDocument pdfDoc = document.getPdfDocument();
PdfPage page = pdfDoc.getPage(pdfDoc.getNumberOfPages());
float width = page.getPageSize().getWidth();
p.addTabStops(new TabStop(width - document.getRightMargin(), TabAlignment.RIGHT, new DottedLine()));
Tab tab = new Tab();
p.add(tab);
p.add(StringUtils.defaultString(catalog.getPageNum(), ""));
// 添加 目录跳转
// //Add destination
// String destinationKey = "p" + (pdfDoc.getNumberOfPages() - 1);
// PdfArray destinationArray = new PdfArray();
// destinationArray.add(page.getPdfObject());
// destinationArray.add(PdfName.XYZ);
// destinationArray.add(new PdfNumber(0));
// destinationArray.add(new PdfNumber(page.getMediaBox().getHeight()));
// destinationArray.add(new PdfNumber(1));
// pdfDoc.addNameDestination(destinationKey, destinationArray);
// //Add TOC line with bookmark
// Paragraph p = new Paragraph();
// p.addTabStops(new TabStop(540, TabAlignment.RIGHT, new DottedLine()));
// p.add(entry.getKey());
// p.add(new Tab());
// p.add(String.valueOf(pdfDoc.getNumberOfPages() - 1));
// p.setProperty(Property.ACTION, PdfAction.createGoTo(destinationKey));
document.add(p);
_deep++;
}
addCatalog(document, catalog.getChildren(), index, _deep, font);
}
}
/**
* 添加页码
* @author sunwen
* @since 2019/12/25
*/
private class PageIndexEvent implements IEventHandler{
private PdfFont font;
PageIndexEvent(PdfFont font){
this.font = font;
}
@Override
public void handleEvent(Event event) {
PdfDocumentEvent docEvent = (PdfDocumentEvent) event;
PdfPage page = docEvent.getPage();
int pageNum = docEvent.getDocument().getPageNumber(page);
PdfCanvas canvas = new PdfCanvas(page);
canvas.beginText();
canvas.setFontAndSize(font, 12);
canvas.beginMarkedContent(PdfName.Artifact);
Rectangle rectangle = page.getPageSize();
float width = rectangle.getWidth();
String text = String.valueOf(pageNum);
canvas.moveText((width - 12 * text.length()) / 2, (45 - 12) / 2f);//计算位置 底部边距内居中
canvas.showText(text);
canvas.endText();
canvas.stroke();
// canvas.addXObject(template, 0, 0);//模板占位符写入共几页
canvas.endMarkedContent();
canvas.release();
}
}
/**
* 设置表格换页属性
* @author sunwen
* @since 2019/12/25
*/
private static void setTable(IElement element){
if(element instanceof Table){
Table table = (Table) element;
int rowNum = table.getNumberOfRows();
int colNum = table.getNumberOfColumns();
for(int i = 0; i < rowNum; i++){
for(int j = 0; j < colNum; j++){
Cell cell = table.getCell(i, j);
if(cell != null){
cell.setKeepTogether(true);
}
}
}
}
}
private static class Catalog{
private String title;//标题为空将视为纯内容
private int pageNum;
private List<Catalog> children;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getPageNum() {
return pageNum;
}
public void setPageNum(int pageNum) {
this.pageNum = pageNum;
}
public List<Catalog> getChildren() {
return children;
}
public Catalog nextCatalog() {
if(children == null){
children = new ArrayList<>();
}
Catalog c = new Catalog();
children.add(c);
return c;
}
}
}html实体类
java
import java.util.List;
/**
* html页
* @author sunwen
* @since 2020/12/10
*/
public class HtmlSheetDto {
public enum Type{
PDF, WORD
}
private String title;//页面标题(标题为空将视为纯内容,不计入目录)
private Boolean showtitle;//是否显示标题(内容中不显示该标题,和是否计入目录无关)
private Boolean newpage;//当前页内容是否需要另起一页
private String pagesize; //页面大小 例如 A4
private boolean rotate; //是否旋转90度
private Integer[] margins; //页边距单位像素
private String image;//当有图片时图片排在html前面,标题为图片标题(默认居中黑体三号字体,且不计入文档标题序列)
private String html;//
private List<HtmlSheetDto> children;//子页面可不设置pagerSize、rotate、margins参照父页面
}ExcelUtil
java
import com.commnetsoft.commons.utils.UUIDUtils;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.exception.MicroRuntimeException;
import com.commnetsoft.file.converter.AbstractFileConverter;
import org.apache.poi.hssf.converter.ExcelToHtmlConverter;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.DirectoryEntry;
import org.apache.poi.poifs.filesystem.DocumentEntry;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* @ClassName ExcelUtil
* @Author wujs
* @Date 2020/9/24 10:49
* @Version 1.0
*/
public class ExcelUtil {
/**
* excel转txt
*
* @param inputStream
* @param targetType
* @param sourceType
* @return java.io.File
* @author wujs
* @date 2020/9/28 18:25
*/
public static File excelToTxt(InputStream inputStream, String targetType, String sourceType) throws Exception {
File tempDirPath = new File(System.getProperty("java.io.tmpdir"));
File pdfFile = new File(tempDirPath, UUIDUtils.generate() + "." + targetType);
Path pdfPath = Paths.get(pdfFile.getPath());
//创建Excel工作薄
Workbook work = WorkbookFactory.create(inputStream);
work.createCellStyle();
BufferedWriter bufferedWriter = java.nio.file.Files.newBufferedWriter(pdfPath, Charset.forName("UTF-8"));
if (null == work) {
throw new Exception("创建Excel工作薄为空!");
}
Sheet sheet = null;
Row row = null;
for (int i = 0; i < work.getNumberOfSheets(); i++) {
sheet = work.getSheetAt(i);
if (sheet == null) {
continue;
}
int hf = sheet.getFirstRowNum();
int hl = sheet.getLastRowNum();
if (hf > hl) {
continue;
}
for (int j = hf; j <= hl; j++) {
row = sheet.getRow(j);
if (row == null) {
continue;
}
StringBuilder strb = new StringBuilder();
for (int y = row.getFirstCellNum(); y < row.getLastCellNum(); y++) {
String s = excelTime(row.getCell(y));
if (y == row.getLastCellNum() - 1) {
strb.append(s + "\n");
} else {
strb.append(s + "\t");
}
}
bufferedWriter.append(strb.toString());
strb = null;
}
}
work.close();
bufferedWriter.close();
inputStream.close();
return pdfFile;
}
public static String excelTime(Cell cell) {
String guarantee_time = "";
try {
if (DateUtil.isCellDateFormatted(cell)) {
//用于转化为日期格式
Date d = cell.getDateCellValue();
DateFormat formater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
guarantee_time = formater.format(d);
return guarantee_time;
}
} catch (Exception e) {
}
return cell == null ? guarantee_time : cell.toString();
}
/**
* excel转pdf
*
* @param inputStream
* @param targetType
* @param sourceType
* @return java.io.File
* @author wujs
* @date 2020/9/28 18:03
*/
public static File excelTopdf(InputStream inputStream, String targetType, String sourceType) throws IOException {
// //设置页面大小
// Rectangle rectPageSize = new Rectangle(PageSize.A4);// 定义A4页面大小
// rectPageSize = rectPageSize.rotate(); //横版
// Document document = new Document(rectPageSize, -80, -80, 50, 0); //边距
// File tempDirPath = new File(System.getProperty("java.io.tmpdir"));
// File pdfFile = new File(tempDirPath, UUIDUtils.generate() + "." + targetType);
// PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(pdfFile));
//
// //字体设置
// BaseFont bf = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
//
// //创建Font对象,将基础字体对象,字体大小,字体风格
// Font font = new Font(bf, 13, Font.NORMAL);
// int rowNum = 0;
// int colNum = 0;
//
// Workbook work = WorkbookFactory.create(inputStream);
// Sheet sheet = null;
// Row row = null;
// Cell cell = null;
// try {
// sheet = work.getSheetAt(0);
// int column = sheet.getRow(0).getLastCellNum();
// int rows = sheet.getPhysicalNumberOfRows();
//
// //下面是找出表格中的空行和空列
// List nullCol = new ArrayList<>();
// List nullRow = new ArrayList<>();
// for (int j = 0; j < column; j++) {
// int nullColNum = 0;
// for (int i = 0; i < rows; i++) {
// row = sheet.getRow(i);
// if (null == row) {
// continue;
// }
// cell = row.getCell(j);
// if (cell == null || (cell.getCellType() == CellType.STRING) && "".equals(cell.getStringCellValue())) {
// nullColNum++;
// }
// }
// if (nullColNum == rows) {
// nullCol.add(j);
// }
// }
//
// for (int i = 0; i < rows; i++) {
// int nullRowNum = 0;
// for (int j = 0; j < column; j++) {
// row = sheet.getRow(i);
// if (null == row) {
// continue;
// }
// cell = row.getCell(j);
// if (cell == null || (cell.getCellType() == CellType.STRING) && "".equals(cell.getStringCellValue())) {
// nullRowNum++;
// }
// }
// if (nullRowNum == column) {
// nullRow.add(i);
// }
// }
// PdfPTable table = new PdfPTable(column - sheet.getRow(0).getFirstCellNum());
// List<CellRangeAddress> ranges = sheet.getMergedRegions();
//
// PdfPCell cell1 = null;
// String str = null;
// for (int i = sheet.getFirstRowNum(); i < rows; i++) {
// if (nullRow.contains(i)) { //如果这一行是空行,这跳过这一行
// continue;
// }
// for (int j = sheet.getRow(0).getFirstCellNum(); j < column; j++) {
// if (nullCol.contains(j)) { //如果这一列是空列,则跳过这一列
// continue;
// }
// boolean flag = true;
// row = sheet.getRow(i);
// if (null == row) {
// continue;
// }
// cell = row.getCell(j);
// if (null == cell) {
// continue;
// }
// if (cell.getCellType() == CellType.NUMERIC) {
// str = cell.getNumericCellValue() + "";
// } else {
// str = cell.getStringCellValue();
// }
// for (CellRangeAddress range : ranges) { //合并的单元格判断和处理
// if (j >= range.getFirstColumn() && j <= range.getLastColumn() && i >= range.getFirstRow()
// && i <= range.getLastRow()) {
// if (str == null || "".equals(str)) {
// flag = false;
// break;
// }
// rowNum = range.getLastRow() - range.getFirstRow() + 1;
// colNum = range.getLastColumn() - range.getFirstColumn() + 1;
// cell1 = mergeCell(str, font, rowNum, colNum);
// table.addCell(cell1);
// flag = false;
// break;
// }
// }
// if (flag) {
// table.addCell(getPDFCell(str, font));
// }
// }
// }
// document.open();
// document.add(table);
// document.close();
// return pdfFile;
// } catch (Exception e) {
// e.printStackTrace();
// } finally {
// inputStream.close();
// writer.close();
// }
// return null;
throw new MicroRuntimeException(CommonError.unimplement);
}
// public static PdfPCell mergeCell(String str, Font font, int i, int j) {
//
// PdfPCell cell = new PdfPCell(new Paragraph(str, font));
// cell.setMinimumHeight(25);
// cell.setHorizontalAlignment(Element.ALIGN_CENTER);
// cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
// cell.setRowspan(i);
// cell.setColspan(j);
//
// return cell;
// }
//
// public static PdfPCell getPDFCell(String string, Font font) {
// //创建单元格对象,将内容与字体放入段落中作为单元格内容
// PdfPCell cell = new PdfPCell(new Paragraph(string, font));
// cell.setHorizontalAlignment(Element.ALIGN_CENTER);
// cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
//
// //设置最小单元格高度
// cell.setMinimumHeight(25);
// return cell;
// }
public static File excelToWord(InputStream inputStream, String targetType, String sourceType) {
ByteArrayOutputStream outStream = null;
try {
HSSFWorkbook excelBook = new HSSFWorkbook();
//判断Excel文件将07+版本转换为03版本
if (AbstractFileConverter.FILE_TYPE_XLS.equals(sourceType)) { //Excel 2003
excelBook = new HSSFWorkbook(inputStream);
} else if (AbstractFileConverter.FILE_TYPE_XLSX.equals(sourceType)) { // Excel 2007/2010
Transform xls = new Transform();
XSSFWorkbook workbookOld = new XSSFWorkbook(inputStream);
xls.transformXSSF(workbookOld, excelBook);
}
ExcelToHtmlConverter excelToHtmlConverter = new ExcelToHtmlConverter(DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument());
//去掉Excel头行
excelToHtmlConverter.setOutputColumnHeaders(false);
//去掉Excel行号
excelToHtmlConverter.setOutputRowNumbers(false);
excelToHtmlConverter.processWorkbook(excelBook);
org.w3c.dom.Document document = excelToHtmlConverter.getDocument();
outStream = new ByteArrayOutputStream();
DOMSource domSource = new DOMSource(document);
StreamResult streamResult = new StreamResult(outStream);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer serializer = tf.newTransformer();
serializer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
serializer.setOutputProperty(OutputKeys.INDENT, "yes");
serializer.setOutputProperty(OutputKeys.METHOD, "html");
serializer.transform(domSource, streamResult);
//Excel转换成Html
String content = new String(outStream.toByteArray());
return writeWordFile(content, targetType);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
outStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
public static File writeWordFile(String content, String targetType) throws Exception {
ByteArrayInputStream byteArrayInputStream = null;
FileOutputStream outputStream = null;
//根据实际情况写路径
try {
File tempDirPath = new File(System.getProperty("java.io.tmpdir"));
File wordFile = new File(tempDirPath, UUIDUtils.generate() + "." + targetType);
byte[] contentBytes = content.getBytes();
byteArrayInputStream = new ByteArrayInputStream(contentBytes);
POIFSFileSystem poifs = new POIFSFileSystem();
DirectoryEntry directory = poifs.getRoot();
DocumentEntry documentEntry = directory.createDocument("WordDocument", byteArrayInputStream);
outputStream = new FileOutputStream(wordFile);
poifs.writeFilesystem(outputStream);
byteArrayInputStream.close();
outputStream.close();
return wordFile;
} catch (IOException e) {
e.printStackTrace();
} finally {
if (outputStream != null) outputStream.close();
if (byteArrayInputStream != null) byteArrayInputStream.close();
}
return null;
}
public String readFile(String filename) throws Exception {
StringBuffer buffer = new StringBuffer("");
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(filename));
buffer = new StringBuffer();
while (br.ready())
buffer.append((char) br.read());
} catch (Exception e) {
e.printStackTrace();
} finally {
if (br != null) br.close();
}
return buffer.toString();
}
}ChineseSplitCharaters
java
import com.itextpdf.io.font.otf.Glyph;
import com.itextpdf.io.font.otf.GlyphLine;
import com.itextpdf.layout.splitting.ISplitCharacters;
/**
* IText PDF中文换行规则
* @author sunwen
* @since 2020/12/18
*/
public class ChineseSplitCharaters implements ISplitCharacters {
/**
* An instance of the chinese SplitCharacter.
*/
public static final ChineseSplitCharaters instance = new ChineseSplitCharaters();
// line of text cannot start or end with this character
static final char u2060 = '\u2060'; // - ZERO WIDTH NO BREAK SPACE
// a line of text cannot start with any following characters in
// NOT_BEGIN_CHARACTERS[]
static final char u30fb = '\u30fb'; // ・ - KATAKANA MIDDLE DOT
static final char u2022 = '\u2022'; // • - BLACK SMALL CIRCLE (BULLET)
static final char uff65 = '\uff65'; // ・ - HALFWIDTH KATAKANA MIDDLE DOT
static final char u300d = '\u300d'; // 」 - RIGHT CORNER BRACKET
static final char uff09 = '\uff09'; // ) - FULLWIDTH RIGHT PARENTHESIS
static final char u0021 = '\u0021'; // ! - EXCLAMATION MARK
static final char u0025 = '\u0025'; // % - PERCENT SIGN
static final char u0029 = '\u0029'; // ) - RIGHT PARENTHESIS
static final char u002c = '\u002c'; // , - COMMA
static final char u002e = '\u002e'; // . - FULL STOP
static final char u003f = '\u003f'; // ? - QUESTION MARK
static final char u005d = '\u005d'; // ] - RIGHT SQUARE BRACKET
static final char u007d = '\u007d'; // } - RIGHT CURLY BRACKET
static final char uff61 = '\uff61'; // 。 - HALFWIDTH IDEOGRAPHIC FULL STOP
static final char uff70 = '\uff70'; // ー - HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK
static final char uff9e = '\uff9e'; // ゙ - HALFWIDTH KATAKANA VOICED SOUND MARK
static final char uff9f = '\uff9f'; // ゚ - HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK
static final char u3001 = '\u3001'; // 、 - IDEOGRAPHIC COMMA
static final char u3002 = '\u3002'; // 。 - IDEOGRAPHIC FULL STOP
static final char uff0c = '\uff0c'; // , - FULLWIDTH COMMA
static final char uff0e = '\uff0e'; // . - FULLWIDTH FULL STOP
static final char uff1a = '\uff1a'; // : - FULLWIDTH COLON
static final char uff1b = '\uff1b'; // ; - FULLWIDTH SEMICOLON
static final char uff1f = '\uff1f'; // ? - FULLWIDTH QUESTION MARK
static final char uff01 = '\uff01'; // ! - FULLWIDTH EXCLAMATION MARK
static final char u309b = '\u309b'; // ゛ - KATAKANA-HIRAGANA VOICED SOUND MARK
static final char u309c = '\u309c'; // ゜ - KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
static final char u30fd = '\u30fd'; // ヽ - KATAKANA ITERATION MARK
static final char u2019 = '\u2019'; // ’ - RIGHT SINGLE QUOTATION MARK
static final char u201d = '\u201d'; // ” - RIGHT DOUBLE QUOTATION MARK
static final char u3015 = '\u3015'; // 〕 - RIGHT TORTOISE SHELL BRACKET
static final char uff3d = '\uff3d'; // ] - FULLWIDTH RIGHT SQUARE BRACKET
static final char uff5d = '\uff5d'; // } - FULLWIDTH RIGHT CURLY BRACKET
static final char u3009 = '\u3009'; // 〉 - RIGHT ANGLE BRACKET
static final char u300b = '\u300b'; // 》 - RIGHT DOUBLE ANGLE BRACKET
static final char u300f = '\u300f'; // 』 - RIGHT WHITE CORNER BRACKET
static final char u3011 = '\u3011'; // 】 - RIGHT BLACK LENTICULAR BRACKET
static final char u00b0 = '\u00b0'; // ° - DEGREE SIGN
static final char u2032 = '\u2032'; // ′ - PRIME
static final char u2033 = '\u2033'; // ″ - DOUBLE PRIME
static final char[] NOT_BEGIN_CHARACTERS = new char[] { u30fb, u2022, uff65, u300d, uff09, u0021, u0025, u0029,
u002c, u002e, u003f, u005d, u007d, uff61, uff70, uff9e, uff9f, u3001, u3002, uff0c, uff0e, uff1a, uff1b,
uff1f, uff01, u309b, u309c, u30fd, u2019, u201d, u3015, uff3d, uff5d, u3009, u300b, u300f, u3011, u00b0,
u2032, u2033, u2060 };
// a line of text cannot end with any following characters in
// NOT_ENDING_CHARACTERS[]
static final char u0024 = '\u0024'; // $ - DOLLAR SIGN
static final char u0028 = '\u0028'; // ( - LEFT PARENTHESIS
static final char u005b = '\u005b'; // [ - LEFT SQUARE BRACKET
static final char u007b = '\u007b'; // { - LEFT CURLY BRACKET
static final char u00a3 = '\u00a3'; // £ - POUND SIGN
static final char u00a5 = '\u00a5'; // ¥ - YEN SIGN
static final char u201c = '\u201c'; // “ - LEFT DOUBLE QUOTATION MARK
static final char u2018 = '\u2018'; // ‘ - LEFT SINGLE QUOTATION MARK
static final char u300a = '\u300a'; // 《 - LEFT DOUBLE ANGLE BRACKET
static final char u3008 = '\u3008'; // 〈 - LEFT ANGLE BRACKET
static final char u300c = '\u300c'; // 「 - LEFT CORNER BRACKET
static final char u300e = '\u300e'; // 『 - LEFT WHITE CORNER BRACKET
static final char u3010 = '\u3010'; // 【 - LEFT BLACK LENTICULAR BRACKET
static final char u3014 = '\u3014'; // 〔 - LEFT TORTOISE SHELL BRACKET
static final char uff62 = '\uff62'; // 「 - HALFWIDTH LEFT CORNER BRACKET
static final char uff08 = '\uff08'; // ( - FULLWIDTH LEFT PARENTHESIS
static final char uff3b = '\uff3b'; // [ - FULLWIDTH LEFT SQUARE BRACKET
static final char uff5b = '\uff5b'; // { - FULLWIDTH LEFT CURLY BRACKET
static final char uffe5 = '\uffe5'; // ¥ - FULLWIDTH YEN SIGN
static final char uff04 = '\uff04'; // $ - FULLWIDTH DOLLAR SIGN
static final char[] NOT_ENDING_CHARACTERS = new char[] { u0024, u0028, u005b, u007b, u00a3, u00a5, u201c, u2018,
u3008, u300a, u300c, u300e, u3010, u3014, uff62, uff08, uff3b, uff5b, uffe5, uff04, u2060 };
@Override
public boolean isSplitCharacter(GlyphLine text, int glyphPos) {
if (!text.get(glyphPos).hasValidUnicode()) {
return false;
}
Glyph glyph = text.get(glyphPos);
char charCode = glyph.getUnicodeChars()[0];
//Check if a hyphen proceeds a digit to denote negative value
if ((glyphPos == 0) && (charCode == '-') && (text.size() - 1 > glyphPos) && (isADigitChar(text, glyphPos + 1))) {
return false;
}
int next = glyphPos + 1;
if (next < text.size()) {//下一个是标点,不能分隔
Glyph nextGlyph = text.get(next);
char charNext = nextGlyph.getUnicodeChars()[0];
for (char not_begin_character : NOT_BEGIN_CHARACTERS) {
if (charNext == not_begin_character) {
return false;
}
}
}
for (char not_ending_character : NOT_ENDING_CHARACTERS) {
if (charCode == not_ending_character) {
return false;
}
}
for (char not_ending_character : NOT_BEGIN_CHARACTERS) {
if (charCode == not_ending_character) {
return true;
}
}
return (charCode <= ' ' || charCode == '-' || charCode == '\u2010'
|| (charCode >= 0x2002 && charCode <= 0x200b)
|| (charCode >= 0x2e80 && charCode < 0xd7a0)
|| (charCode >= 0xf900 && charCode < 0xfb00)
|| (charCode >= 0xfe30 && charCode < 0xfe50)
|| (charCode >= 0xff61 && charCode < 0xffa0));
}
private boolean isADigitChar(GlyphLine text, int glyphPos) {
return Character.isDigit(text.get(glyphPos).getChars()[0]);
}
}DocxHelper
java
import com.aspose.words.SaveFormat;
import com.commnetsoft.commons.utils.UUIDUtils;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.exception.MicroRuntimeException;
import com.commnetsoft.file.model.HtmlSheetDto;
import com.itextpdf.io.codec.Base64;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.docx4j.Docx4J;
import org.docx4j.Docx4jProperties;
import org.docx4j.TraversalUtil;
import org.docx4j.convert.in.xhtml.XHTMLImporterImpl;
import org.docx4j.dml.wordprocessingDrawing.Inline;
import org.docx4j.finders.RangeFinder;
import org.docx4j.model.structure.PageDimensions;
import org.docx4j.model.structure.PageSizePaper;
import org.docx4j.openpackaging.exceptions.Docx4JException;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.BinaryPartAbstractImage;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.docx4j.openpackaging.parts.WordprocessingML.NumberingDefinitionsPart;
import org.docx4j.wml.*;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.*;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import java.io.*;
import java.math.BigInteger;
import java.util.*;
/**
* @ClassName WordHelper
* @Author wuzm
* @Date 2020/12/28 14:46
* @Version 1.0
*/
@Component
public class DocxHelper {
private static final Logger log = LoggerFactory.getLogger(DocxHelper.class);
private static final ObjectFactory factory = new ObjectFactory();
private static final int[] DEFAULT_MARGIN = {1440, 1800, 1440, 1800};
public void convertBook(HtmlSheetDto htmlSheetDto, OutputStream out, boolean autoOrdinal) throws Exception {
boolean needCatalog = isNeedCatalog(htmlSheetDto, 0);
WordprocessingMLPackage wpmlPackage = createWPMLPackage(htmlSheetDto.getPagesize(), BooleanUtils.isTrue(htmlSheetDto.isRotate()), htmlSheetDto.getMargins(),true);
addBookSheet(wpmlPackage, htmlSheetDto, 0, 1, needCatalog, autoOrdinal);
if(needCatalog){
File file = new File(System.getProperty("java.io.tmpdir"), UUIDUtils.generate());
wpmlPackage.save(new FileOutputStream(file));
//更新目录
com.aspose.words.Document doc = new com.aspose.words.Document(new FileInputStream(file));
doc.updateFields();
//如果需要自动编号,目录生成之后再删除标题上的编号
if(autoOrdinal){
doc.save(new FileOutputStream(file), SaveFormat.DOCX);
if (!removeTitleNum(file, out)) {
doc.save(out, SaveFormat.DOCX);
}
}else{
doc.save(out, SaveFormat.DOCX);
}
file.delete();
}else{
wpmlPackage.save(out);
}
}
public void convertBook(HtmlSheetDto htmlSheetDto, File file, boolean autoOrdinal) throws Exception {
WordprocessingMLPackage wpmlPackage = createWPMLPackage(htmlSheetDto.getPagesize(), BooleanUtils.isTrue(htmlSheetDto.isRotate()), htmlSheetDto.getMargins(), true);
//添加目录
boolean needCatalog = isNeedCatalog(htmlSheetDto, 0);
addBookSheet(wpmlPackage, htmlSheetDto, 0, 1, needCatalog, autoOrdinal);
wpmlPackage.save(new FileOutputStream(file));
if (needCatalog) {
//更新目录
com.aspose.words.Document doc = new com.aspose.words.Document(new FileInputStream(file));
doc.updateFields();
doc.save(new FileOutputStream(file), SaveFormat.DOCX);
if(autoOrdinal){
removeTitleNum(file);
}
}
}
/**
* 移除文件标题上的序号,并将结果写出到输出流中
* @param file 生成目录后的文件
* @param out 输出流
* @return boolean 是否有内容被移除了
* @author wuzm
* @date 2021/1/14
*/
private boolean removeTitleNum(File file, OutputStream out) throws Docx4JException, FileNotFoundException {
WordprocessingMLPackage loadFile = WordprocessingMLPackage.load(new FileInputStream(file));
boolean hasRemoved = removeTitleNum(loadFile);
if (hasRemoved) {
Docx4J.save(loadFile, out);
}
return hasRemoved;
}
/**
* 移除文件标题上的序号,移除后的内容覆盖原文件
* @param file 生成目录后的文件
* @return boolean 是否有内容被移除了
* @author wuzm
* @date 2021/1/14
*/
private boolean removeTitleNum(File file) throws Docx4JException, FileNotFoundException {
WordprocessingMLPackage loadFile = WordprocessingMLPackage.load(new FileInputStream(file));
boolean hasRemoved = removeTitleNum(loadFile);
if (hasRemoved) {
Docx4J.save(loadFile, new FileOutputStream(file));
}
return hasRemoved;
}
/**
* 移除文件标题上的序号
* @param loadFile docx4j加载后的内容
* @return boolean 是否有内容被移除了
* @author wuzm
* @date 2021/1/14
*/
private boolean removeTitleNum(WordprocessingMLPackage loadFile) {
boolean hasRemoved = false;
List<Object> contents = loadFile.getMainDocumentPart().getContent();
RangeFinder rt = new RangeFinder("CTBookmark", "CTMarkupRange");
new TraversalUtil(contents, rt);
for (CTBookmark bm : rt.getStarts()) {
Object parent = bm.getParent();
if (!(parent instanceof P)) {
continue;
}
P parentP = (P) parent;
PPr pPr = parentP.getPPr();
if (null == pPr) {
continue;
}
PPrBase.NumPr numPr = pPr.getNumPr();
if (null == numPr) {
continue;
}
//移除NumPr
pPr.setNumPr(null);
//缩进处理
PPrBase.Ind ind = pPr.getInd();
if (null == ind) {
continue;
}
BigInteger left = ind.getLeft();
BigInteger hanging = ind.getHanging();
if (null != left && (!BigInteger.ZERO.equals(left)) && (left.equals(hanging))) {
pPr.setInd(null);
}
if (!hasRemoved) {
hasRemoved = true;
}else{
removeCatalogTab(loadFile);
}
}
return hasRemoved;
}
/**
* 移除目录中的tab
* @param loadFile 生成目录后的文件
* @author wuzm
* @date 2021/1/15
*/
private void removeCatalogTab(WordprocessingMLPackage loadFile) {
List<Object> contents = loadFile.getMainDocumentPart().getContent();
for (Object content : contents) {
if(!(content instanceof SdtBlock)){
continue;
}
SdtBlock sdtBlock = (SdtBlock) content;
SdtContent sdtContent = sdtBlock.getSdtContent();
List<Object> sdtContents = sdtContent.getContent();
for (Object sdtObjContent : sdtContents) {
if(!(sdtObjContent instanceof P)){
continue;
}
P p = (P) sdtObjContent;
boolean isBreak = false;
List<Object> pContentObjs = p.getContent();
Iterator<Object> iterator = pContentObjs.iterator();
while (iterator.hasNext()) {
if(isBreak){
break;
}
Object pContentObj = iterator.next();
if(!(pContentObj instanceof R)){
continue;
}
R r = (R) pContentObj;
List<Object> rContentObjs = r.getContent();
JAXBElement rFristContent = (JAXBElement)rContentObjs.get(0);
if(StringUtils.equals("tab",rFristContent.getName().getLocalPart())){
//含有noProof属性的将当前元素移除并跳出循环
RPr rPr = r.getRPr();
if(null != rPr.getNoProof()){
iterator.remove();
isBreak = true;
}
}
}
}
break;
}
}
/**
* 判断是否需要添加目录
* @param htmlSheetDto html原内容
* @return boolean
* @author wuzm
* @date 2021/1/12
*/
private boolean isNeedCatalog(HtmlSheetDto htmlSheetDto,int level){
if (level > 0 && StringUtils.isNotEmpty(htmlSheetDto.getTitle()) && StringUtils.isEmpty(htmlSheetDto.getImage())) {
return true;
}
level += 1;
if(CollectionUtils.isNotEmpty(htmlSheetDto.getChildren())){
for (HtmlSheetDto childHtmlSheetDto : htmlSheetDto.getChildren()) {
if(isNeedCatalog(childHtmlSheetDto,level)){
return true;
}
}
}
return false;
}
private int addBookSheet(WordprocessingMLPackage wpmlPackage, HtmlSheetDto htmlSheetDto, int level, int chapterCount, boolean isNeedCatalog, boolean autoOrdinal) throws Exception {
List<Object> contents = wpmlPackage.getMainDocumentPart().getContent();
if (level > 0 && BooleanUtils.isTrue(htmlSheetDto.getNewpage())) {
chapterCount += 1;
P p = createNewPage(htmlSheetDto);
SectPr sectPr = p.getPPr().getSectPr();
//第章节插入页码从1开始
if (chapterCount == 3) {
PageNumHelper.addPageNumFooter(wpmlPackage, sectPr, 0);
//设置开始页码
sectPr.setPgNumType(getPageNum(1));
}
contents.add(p);
}
addSheet(wpmlPackage, htmlSheetDto, level, true, autoOrdinal);
//添加目录
if (level == 0 && isNeedCatalog) {
//先添加分页隔离封面
P p = createNewPage(htmlSheetDto);
contents.add(p);
//插入空目录
Docx4jProperties.setProperty("docx4j.toc.TocStyles.xml", "docx/TocStyles.xml");
TocGenerator tocGenerator = new TocGenerator(wpmlPackage);
int index = wpmlPackage.getMainDocumentPart().getContent().size();
tocGenerator.generateToc(index, "TOC \\o \"1-3\" \\h \\z \\u ", false);
}
level += 1;
//递归添加子页面
if (CollectionUtils.isNotEmpty(htmlSheetDto.getChildren())) {
for (HtmlSheetDto childSheet : htmlSheetDto.getChildren()) {
chapterCount = addBookSheet(wpmlPackage, childSheet, level, chapterCount, isNeedCatalog, autoOrdinal);
}
}
return chapterCount;
}
private void addSheet(WordprocessingMLPackage wpmlPackage, HtmlSheetDto htmlSheetDto, int level,boolean isBook, boolean autoOrdinal) throws Exception {
MainDocumentPart mainDocumentPart = wpmlPackage.getMainDocumentPart();
List<Object> contents = mainDocumentPart.getContent();
boolean showTitle = BooleanUtils.isTrue(htmlSheetDto.getShowtitle());
String title = htmlSheetDto.getTitle();
String image = htmlSheetDto.getImage();
//判断是否需要将转换后的第一个内容标记为目录,只对小册子生效
boolean relateFirstParagraphToCatalog = false;
//添加标题(title不为空,image为空)
if (level > 0 && StringUtils.isNotEmpty(title) && StringUtils.isEmpty(image)) {
//如果显示目录,则创建对应层级的目录,如果不显示,则将转换后的第一段设置为目录(第一段必须是标题字段,如果不是则手动创建一个)
if(showTitle){
addTitle(mainDocumentPart, level, title, autoOrdinal);
}else if(isBook){
relateFirstParagraphToCatalog = true;
}
}
//添加图片
if (StringUtils.isNotEmpty(image)) {
byte[] bytes;
String[] strParts = image.split(",");
if (strParts.length == 2 && ("data:image/gif;base64".equals(strParts[0]) || "data:image/png;base64".equals(strParts[0]) || "data:image/jpeg;base64".equals(strParts[0]))) {
bytes = Base64.decode(strParts[1]);
} else {
throw new MicroRuntimeException(CommonError.illegal_args, "不支持的图片格式");
}
//添加图片标题
if (showTitle && StringUtils.isNotEmpty(htmlSheetDto.getTitle())) {
P text = createText(JcEnumeration.CENTER, htmlSheetDto.getTitle(),"黑体",32);
PPr pPr = text.getPPr();
pPr.setKeepNext(new BooleanDefaultTrue());
mainDocumentPart.getContent().add(text);
}
String filenameHint = htmlSheetDto.getTitle();
String altText = htmlSheetDto.getTitle();
int id1 = RandomUtils.nextInt(500, Integer.MAX_VALUE);
int id2 = RandomUtils.nextInt(500, Integer.MAX_VALUE);
P p = newImage(wpmlPackage, bytes, filenameHint, altText, id1, id2);
contents.add(p);
}
String html = htmlSheetDto.getHtml();
if(StringUtils.isNotEmpty(html)){
List<Object> convertContents = new XHTMLImporterImpl(wpmlPackage).convert(htmlToXhtml(html), null, getExtentStyle(htmlSheetDto));
//设置转换后的第一段落中内容是文本的设置成目录关联内容
if(relateFirstParagraphToCatalog){
markAsCatalogOutLevel(mainDocumentPart, convertContents, level, title, autoOrdinal);
}
contents.addAll(convertContents);
}
}
/**
* 将第一个段落设置为目录外链接
* 层级大于6的设置成6
* @param mainDocumentPart 文档内容
* @param convertContents 转换后的内容
* @param level 目录层级
* @param title 标题
* @author wuzm
* @date 2021/1/13
*/
private void markAsCatalogOutLevel(MainDocumentPart mainDocumentPart, List<Object> convertContents, Integer level, String title, boolean autoOrdinal) {
if (null == level || level == 0) {
return;
}
if (CollectionUtils.isEmpty(convertContents)) {
return;
}
//第一个段落内容如果不是段落则添加标题
Object firstContent = convertContents.get(0);
if(!(firstContent instanceof P)){
addTitle(mainDocumentPart, level, title, autoOrdinal);
}else{
//直接将第一段设置成目录外链
P firstP = (P) firstContent;
setOutLevel(firstP, level);
//添加标题
if(autoOrdinal){
addOrdinal(level, autoOrdinal, firstP);
}
}
}
private void setOutLevel(P p,int level){
if(null == p){
return;
}
PPr pPr = p.getPPr();
if(null == pPr){
pPr = factory.createPPr();
p.setPPr(pPr);
}
PPrBase.OutlineLvl outlineLvl = factory.createPPrBaseOutlineLvl();
outlineLvl.setVal(BigInteger.valueOf((level-1)));
pPr.setOutlineLvl(outlineLvl);
}
public void convert(HtmlSheetDto htmlSheetDto, OutputStream out) throws Exception {
WordprocessingMLPackage wpmlPackage = createWPMLPackage(htmlSheetDto.getPagesize(), htmlSheetDto.isRotate(), htmlSheetDto.getMargins(), true);
SectPr sectPr = wpmlPackage.getMainDocumentPart().getContents().getBody().getSectPr();
addEachSheet(wpmlPackage,htmlSheetDto,1);
//添加页码
PageNumHelper.addPageNumFooter(wpmlPackage, sectPr, 1);
wpmlPackage.save(out);
}
private void addEachSheet(WordprocessingMLPackage wpmlPackage, HtmlSheetDto htmlSheetDto, int level) throws Exception {
addSheet(wpmlPackage, htmlSheetDto, level, false, false);
level += 1;
//递归添加子页面
if(CollectionUtils.isNotEmpty(htmlSheetDto.getChildren())){
for (HtmlSheetDto childSheet : htmlSheetDto.getChildren()) {
addEachSheet(wpmlPackage, childSheet, level);
}
}
}
/**
* 将一个html转换成docx文件,不带页码
* @param html html源码
* @param pageSize 页面大小
* @param rotate 是否旋转
* @param margins 边距
* @param out 输出流
* @author wuzm
* @date 2020/12/28
*/
public void convert(String html, String pageSize, boolean rotate, Integer[] margins, OutputStream out) throws Docx4JException, JAXBException {
WordprocessingMLPackage wpmlPackage = createWPMLPackage(pageSize, rotate, margins,false);
//转换html
List<Object> convertContents = new XHTMLImporterImpl(wpmlPackage).convert(htmlToXhtml(html), null);
wpmlPackage.getMainDocumentPart().getContent().addAll(convertContents);
//输出
wpmlPackage.save(out);
}
/**
* html转xhtml
* @param html 源码
* @return java.lang.String
* @author wuzm
* @date 2020/12/30
*/
private String htmlToXhtml(String html){
if(org.apache.commons.lang3.StringUtils.isBlank(html)){
return html;
}
//替换text-decoration-line为text-decoration
html = StringUtils.replace(html, "text-decoration-line", "text-decoration");
org.jsoup.nodes.Document doc = Jsoup.parse(html);
removeEmptyContent(doc);
removeBrElements(doc);
doc.outputSettings().syntax(Document.OutputSettings.Syntax.xml).escapeMode(Entities.EscapeMode.xhtml);
return doc.html();
}
/**
* 移除空的段落
* @author wuzm
* @date 2021/1/29
*/
private void removeEmptyContent(Document doc) {
Elements bodys = doc.getElementsByTag("body");
Iterator<Element> iterator = bodys.iterator();
Set<Node> removeNodes = new HashSet<>();
while (iterator.hasNext()){
Element nextBody = iterator.next();
List<Node> nodes = nextBody.childNodes();
for (Node node : nodes) {
if(isEmptyContentNode(node)){
removeNodes.add(node);
}
}
}
if(removeNodes.size() > 0){
removeNodes.forEach(Node::remove);
}
}
/**
* 处理br标签换行问题
* @author wuzm
* @date 2021/1/8
*/
private void removeBrElements(Document doc) {
Elements brs = doc.getElementsByTag("br");
Iterator<Element> iterator = brs.iterator();
Set<Node> removeNodes = new HashSet<>();
while (iterator.hasNext()){
Element nextBr = iterator.next();
Node node = nextBr.parentNode();
List<Node> childNodes = node.childNodes();
List<Integer> brIndexs = new ArrayList<>();
for (int i = 0; i < childNodes.size(); i++) {
if (StringUtils.equals(childNodes.get(i).nodeName(), "br")) {
brIndexs.add(i);
}
}
Set<Integer> removeNodeIndexs = new HashSet<>();
//获取最后一个br索引
Integer lastBrIndex = brIndexs.get(brIndexs.size() - 1);
//如果最后一个br是父元素的最后一个子元素则移除
if(lastBrIndex == (childNodes.size()-1)){
removeNodeIndexs.add(lastBrIndex);
}else{
//判断该元素后的元素是否都是空元素,如果是,则移除当前元素以及后面的其他元素
boolean isEmpty = true;
for (int i = lastBrIndex+1; i <childNodes.size(); i++){
Node childNode = childNodes.get(i);
if(!isEmptyTextNode(childNode)){
isEmpty = false;
break;
}
}
if(isEmpty){
for (int i = lastBrIndex; i <childNodes.size(); i++){
removeNodeIndexs.add(i);
}
}
}
for (Integer removeNodeIndex : removeNodeIndexs) {
removeNodes.add(childNodes.get(removeNodeIndex));
}
}
for (Node removeNode : removeNodes) {
removeNode.remove();
}
}
/**
* 判断节点是否是空的文本
* @param node 节点
* @return boolean
* @author wuzm
* @date 2021/1/25
*/
private boolean isEmptyTextNode(Node node){
if(null == node){
return true;
}
if(node instanceof TextNode){
TextNode textNode = (TextNode) node;
return textNode.isBlank();
}else{
List<Node> nodes = node.childNodes();
if(null == nodes || nodes.size() == 0){
return true;
}
for (Node childNode : nodes) {
if(!isEmptyTextNode(childNode)){
return false;
}
}
}
return true;
}
/**
* 判断节点是否是空的内容,br/img不算空内容
* @param node
* @return boolean
* @author wuzm
* @date 2021/1/29
*/
private boolean isEmptyContentNode(Node node){
if(null == node){
return true;
}
if(node instanceof TextNode){
TextNode textNode = (TextNode) node;
return textNode.isBlank();
}else if(node.nodeName().equals("img")){
return false;
}else if(node.nodeName().equals("br")){
return false;
}else{
List<Node> nodes = node.childNodes();
if(null == nodes || nodes.size() == 0){
return true;
}
for (Node childNode : nodes) {
if(!isEmptyContentNode(childNode)){
return false;
}
}
}
return true;
}
/**
* 判断节点是否是文本节点并且内容为空
* @param node 被判断的节点
* @return boolean
* @author wuzm
* @date 2021/1/8
*/
private boolean isNodeEmptyContent(Node node){
if(null == node){
return true;
}
if(node instanceof TextNode){
TextNode textNode = (TextNode) node;
return textNode.isBlank();
}
return false;
}
/**
* 创建新的页面
* @param sheet 页面信息
* @return org.docx4j.wml.P
* @author wuzm
* @date 2021/1/8
*/
private P createNewPage(HtmlSheetDto sheet) {
P p = factory.createP();
PPr pPr = factory.createPPr();
//创建章节
SectPr sectPr = createSectPr(sheet);
pPr.setSectPr(sectPr);
p.setPPr(pPr);
return p;
}
/**
* 创建章节
* @param sheet 页面信息
* @return org.docx4j.wml.SectPr
* @author wuzm
* @date 2021/1/8
*/
private SectPr createSectPr(HtmlSheetDto sheet){
//获取页面大小
PageSizePaper pageSizePaper = getPageSizePaper(sheet.getPagesize());
//是否旋转
boolean rotate = BooleanUtils.isTrue(sheet.isRotate());
PageDimensions page = new PageDimensions();
page.setPgSize(pageSizePaper, rotate);
SectPr sectPr = factory.createSectPr();
sectPr.setPgSz( page.getPgSz() );
sectPr.setPgMar( page.getPgMar() );
//重新设置页面边距
resetPgMar(sectPr.getPgMar(),sheet.getMargins());
return sectPr;
}
/**
* 获取页面额外信息设置成样式属性
* @param sheet 页面属性
* @return java.lang.String
* @author wuzm
* @date 2021/1/22
*/
private String getExtentStyle(HtmlSheetDto sheet){
SectPr sectPr = createSectPr(sheet);
StringBuilder sb = new StringBuilder();
//设置页面样式
SectPr.PgSz pgSz = sectPr.getPgSz();
if(null != pgSz){
sb.append("@page{");
BigInteger width = pgSz.getW();
if(null != width && width.intValue() > 0){
sb.append("-fs-page-width:").append(width.intValue()).append(";");
}
BigInteger height = pgSz.getH();
if(null != height && height.intValue() > 0){
sb.append("-fs-page-height:").append(height.intValue()).append(";");
}
STPageOrientation orient = pgSz.getOrient();
if(null != orient && StringUtils.isNotEmpty(orient.value())){
sb.append("-fs-page-orientation:").append(orient.value()).append(";");
}
SectPr.PgMar pgMar = sectPr.getPgMar();
if(null != pgMar){
sb.append("margin:")
.append(pgMar.getTop()).append(" ")
.append(pgMar.getRight()).append(" ")
.append(pgMar.getBottom()).append(" ")
.append(pgMar.getRight()).append(";");
}
sb.append("}");
sb.append(" ");
}
sb.append("body{margin: 0 !important;}");
return sb.toString();
}
/**
* 创建图片
* @param wordMLPackage 文档主体
* @param bytes 图片字节
* @param filenameHint 文件名
* @param altText 文件不存在时候显示内容
* @param id1 文件识别码1
* @param id2 文件识别码2
* @return org.docx4j.wml.P
* @author wuzm
* @date 2021/1/8
*/
private P newImage(WordprocessingMLPackage wordMLPackage, byte[] bytes, String filenameHint, String altText, int id1, int id2) throws Exception {
BinaryPartAbstractImage imagePart = BinaryPartAbstractImage.createImagePart(wordMLPackage, bytes);
Inline inline = imagePart.createImageInline( filenameHint, altText, id1, id2, false);
P p = createNewParagraph(JcEnumeration.CENTER);
R run = factory.createR();
p.getContent().add(run);
Drawing drawing = factory.createDrawing();
run.getContent().add(drawing);
drawing.getAnchorOrInline().add(inline);
return p;
}
private void addTitle(MainDocumentPart mainDocumentPart, Integer level, String title, boolean autoOrdinal) {
P p = createTitle(mainDocumentPart, level , title, autoOrdinal);
mainDocumentPart.getContent().add(p);
}
/**
* 创建标题或者内容段落
* @param mainDocumentPart 文档主文档
* @param level 当前的层级,用于判断添加标题的级别,有效值为1-6, 其他的数值认为是文本内容
* @param title 标题内容
* @return org.docx4j.wml.P
* @author wuzm
* @date 2021/1/13
*/
private P createTitle(MainDocumentPart mainDocumentPart, Integer level, String title, boolean autoOrdinal) {
P p;
//如果层级在1-6则添加标题,其他默认是最低等级标题
if (null != level && level < 7 && level > 0) {
p = mainDocumentPart.createStyledParagraphOfText("Heading" + level, title);
} else {
p = mainDocumentPart.createStyledParagraphOfText("" + 7, title);
}
addOrdinal(level, autoOrdinal, p);
return p;
}
private void addOrdinal(Integer level, boolean autoOrdinal, P p) {
//添加编号
if (autoOrdinal && level > 0 && level < 4) {
PPr pPr = p.getPPr();
if (null == pPr) {
pPr = factory.createPPr();
p.setPPr(pPr);
}
PPrBase.NumPr numPr = factory.createPPrBaseNumPr();
PPrBase.NumPr.Ilvl ilvl = factory.createPPrBaseNumPrIlvl();
ilvl.setVal(BigInteger.valueOf((level-1)));
numPr.setIlvl(ilvl);
PPrBase.NumPr.NumId numId = factory.createPPrBaseNumPrNumId();
numId.setVal(BigInteger.ONE);
numPr.setNumId(numId);
pPr.setNumPr(numPr);
//设置缩进
PPrBase.Ind ind = factory.createPPrBaseInd();
BigInteger hanging;
if (1 == level) {
hanging = BigInteger.valueOf(425);
} else if (level == 2) {
hanging = BigInteger.valueOf(567);
} else {
hanging = BigInteger.valueOf(709);
}
ind.setHanging(hanging);
ind.setLeft(hanging);
ind.setLeftChars(BigInteger.ZERO);
ind.setFirstLineChars(BigInteger.ZERO);
pPr.setInd(ind);
}
}
private void addText(MainDocumentPart mainDocumentPart,JcEnumeration jcEnumeration, String content) {
P p = createText(jcEnumeration, content);
mainDocumentPart.getContent().add(p);
}
private P createText(JcEnumeration jcEnumeration, String content) {
P p = createNewParagraph(jcEnumeration);
R r = factory.createR();
Text text = factory.createText();
text.setValue(content);
r.getContent().add(text);
p.getContent().add(r);
return p;
}
private P createText(JcEnumeration jcEnumeration, String content, String fontType, Integer fontSize) {
P p = createNewParagraph(jcEnumeration);
R r = factory.createR();
Text text = factory.createText();
text.setValue(content);
if(StringUtils.isNotEmpty(fontType) || null != fontSize){
RPr rPr = factory.createRPr();
r.setRPr(rPr);
if(StringUtils.isNotEmpty(fontType)){
RFonts rFonts = factory.createRFonts();
rPr.setRFonts(rFonts);
rFonts.setAscii(fontType);
rFonts.setEastAsia(fontType);
rFonts.setHint(STHint.EAST_ASIA);
}
if(null != fontSize){
HpsMeasure hpsMeasure = factory.createHpsMeasure();
hpsMeasure.setVal(BigInteger.valueOf(fontSize));
rPr.setSz(hpsMeasure);
}
}
r.getContent().add(text);
p.getContent().add(r);
return p;
}
/**
* 创建新的的段落
* @return org.docx4j.wml.P
* @author wuzm
* @date 2020/12/29
*/
private P createNewParagraph(JcEnumeration jcEnumeration){
P p = factory.createP();
//设置居中属性
PPr pPr = factory.createPPr();
Jc jc = factory.createJc();
jc.setVal(jcEnumeration);
pPr.setJc(jc);
p.setPPr(pPr);
return p;
}
/**
* 创建文档
* @param pageSize 页面大小
* @param rotate 是否旋转
* @param margins 边距
* @return org.docx4j.openpackaging.packages.WordprocessingMLPackage
* @author wuzm
* @date 2020/12/28
*/
private WordprocessingMLPackage createWPMLPackage(String pageSize, boolean rotate, Integer[] margins, boolean needPageNum) throws Docx4JException, JAXBException {
PageSizePaper pageSizePaper = getPageSizePaper(pageSize);
Docx4jProperties.setProperty("docx4j.openpackaging.parts.WordprocessingML.NumberingDefinitionsPart.DefaultNumbering", "docx/numbering.xml");
Docx4jProperties.setProperty("docx4j.openpackaging.parts.WordprocessingML.StyleDefinitionsPart.KnownStyles", "docx/KnownStyles.xml");
Docx4jProperties.setProperty("docx4j.openpackaging.parts.WordprocessingML.StyleDefinitionsPart.DefaultStyles", "docx/styles.xml");
WordprocessingMLPackage wMLPackage = WordprocessingMLPackage.createPackage(pageSizePaper, rotate);
//自定义序号样式为层级缩进样式
NumberingDefinitionsPart numberPart = new org.docx4j.openpackaging.parts.WordprocessingML.NumberingDefinitionsPart();
numberPart.unmarshalDefaultNumbering();
wMLPackage.getMainDocumentPart().addTargetPart(numberPart);
SectPr sectPr = wMLPackage.getMainDocumentPart().getContents().getBody().getSectPr();
SectPr.PgMar pgMar = sectPr.getPgMar();
//重新设置页边距
resetPgMar(pgMar, margins);
//判断文档是否需要页码
if(needPageNum){
sectPr.setPgNumType(getPageNum(null));
}
return wMLPackage;
}
/**
* 获取页面大小
* @param pageSize 页面大小类型:A4,A3...
* @return org.docx4j.model.structure.PageSizePaper
* @author wuzm
* @date 2021/1/8
*/
private PageSizePaper getPageSizePaper(String pageSize){
PageSizePaper pageSizePaper;
if(StringUtils.isNotEmpty(pageSize)){
pageSizePaper = PageSizePaper.valueOf(pageSize);
}else{
pageSizePaper = PageSizePaper.A4;
}
return pageSizePaper;
}
/**
* 重新设置文档页边距
* @param pgMar 文档布局属性
* @param margins 新的文档布局
* @author wuzm
* @date 2021/1/8
*/
private void resetPgMar(SectPr.PgMar pgMar, Integer[] margins){
int[] mg = getPgMargin(margins);
int top = mg[0];
int bottom = mg[2];
pgMar.setTop(BigInteger.valueOf(top));
pgMar.setRight(BigInteger.valueOf(mg[1]));
pgMar.setBottom(BigInteger.valueOf(bottom));
pgMar.setLeft(BigInteger.valueOf(mg[3]));
long header = footerHeaderMargin(top);
pgMar.setHeader(BigInteger.valueOf(header));
long footer = footerHeaderMargin(bottom);
pgMar.setFooter(BigInteger.valueOf(footer));
pgMar.setGutter(BigInteger.ZERO);
}
private int[] getPgMargin(Integer[] margins){
int[] mg = {DEFAULT_MARGIN[0], DEFAULT_MARGIN[1], DEFAULT_MARGIN[2], DEFAULT_MARGIN[3]};
if(null != margins){
for (int i = 0; i < mg.length; i++) {
Integer m = margins[i];
if(m == null || m < 0){
continue;
}
mg[i] = margins[i] * 15;
}
}
return mg;
}
private int footerHeaderMargin(int height){
int marging;
if(height > 480 ){
marging = height - 480;
}else {
marging = 0;
}
return marging;
}
/**
* 创建页码
* @param startNum 页码开始的数
* @return org.docx4j.wml.CTPageNumber
* @author wuzm
* @date 2021/1/8
*/
private CTPageNumber getPageNum(Integer startNum){
CTPageNumber pageNumber = factory.createCTPageNumber();
pageNumber.setFmt(NumberFormat.DECIMAL);
if(null != startNum){
pageNumber.setStart(BigInteger.valueOf(startNum));
}
return pageNumber;
}
}PageNumHelper
java
import org.docx4j.XmlUtils;
import org.docx4j.jaxb.Context;
import org.docx4j.openpackaging.exceptions.InvalidFormatException;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.FooterPart;
import org.docx4j.relationships.Relationship;
import org.docx4j.wml.*;
import javax.xml.bind.JAXBException;
/**
* @ClassName PageNumHelper
* @Author wuzm
* @Date 2021/1/5 9:26
* @Version 1.0
*/
public class PageNumHelper {
private static String getPageNumFooterXml(int fromPageNum){
return "<w:p xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" >\n" +
" <w:pPr>\n" +
" <w:pStyle w:val=\"8\"/>\n" +
" <w:jc w:val=\"center\"/>"+
" </w:pPr>\n" +
" <w:r>\n" +
" <w:fldChar w:fldCharType=\"begin\"/>\n" +
" </w:r>\n" +
" <w:r>\n" +
" <w:instrText xml:space=\"preserve\"> PAGE \\* MERGEFORMAT </w:instrText>\n" +
" </w:r>\n" +
" <w:r>\n" +
" <w:fldChar w:fldCharType=\"separate\"/>\n" +
" </w:r>\n" +
" <w:r>\n" +
" <w:t>"+ fromPageNum +"</w:t>\n" +
" </w:r>\n" +
" <w:r>\n" +
" <w:fldChar w:fldCharType=\"end\"/>\n" +
" </w:r>\n" +
"</w:p>";
}
//创建页脚模块
public static void addPageNumFooter(WordprocessingMLPackage wordMLPackage,SectPr sectPr, Integer fromPageNum) throws JAXBException, InvalidFormatException {
Relationship relationship = createFooterPart(wordMLPackage,fromPageNum);
//创建引用
addReferences(sectPr, relationship);
}
public static Relationship createFooterPart(WordprocessingMLPackage wordMLPackage, Integer fromPageNum) throws InvalidFormatException, JAXBException {
FooterPart footerPart = new FooterPart();
Relationship relationship = wordMLPackage.getMainDocumentPart().addTargetPart(footerPart);
footerPart.setJaxbElement(getFtr(fromPageNum));
return relationship;
}
private static Ftr getFtr(Integer fromPageNum) throws JAXBException {
Ftr ftr = Context.getWmlObjectFactory().createFtr();
P p;
if(null == fromPageNum){
p = Context.getWmlObjectFactory().createP();
PPr pPr = Context.getWmlObjectFactory().createPPr();
PPrBase.PStyle pStyle = Context.getWmlObjectFactory().createPPrBasePStyle();
pStyle.setVal("8");
pPr.setPStyle(pStyle);
p.setPPr(pPr);
}else{
p = (P) XmlUtils.unmarshalString(getPageNumFooterXml(fromPageNum));
}
ftr.getContent().add(p);
return ftr;
}
private static void createFooterReference(SectPr sectPr, Relationship relationship){
//创建页码格式
CTPageNumber pageNumber = Context.getWmlObjectFactory().createCTPageNumber();
pageNumber.setFmt(NumberFormat.DECIMAL);
sectPr.setPgNumType(pageNumber);
//添加引用
addReferences(sectPr, relationship);
}
public static void addReferences(SectPr sectPr,Relationship relationship){
FooterReference footerReference = Context.getWmlObjectFactory().createFooterReference();
footerReference.setId(relationship.getId());
footerReference.setType(HdrFtrRef.DEFAULT);
sectPr.getEGHdrFtrReferences().add(footerReference);
}
}TocGenerator
java
import org.docx4j.XmlUtils;
import org.docx4j.jaxb.Context;
import org.docx4j.model.listnumbering.Emulator;
import org.docx4j.model.structure.PageDimensions;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.docx4j.toc.*;
import org.docx4j.toc.switches.SwitchProcessor;
import org.docx4j.wml.*;
import javax.xml.bind.JAXBElement;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @ClassName TocGenerator
* @Author wuzm
* @Date 2021/1/11 15:45
* @Version 1.0
*/
public class TocGenerator extends org.docx4j.toc.TocGenerator {
private WordprocessingMLPackage wordMLPackage;
private SectPr sectPr;
private TocStyles tocStyles;
public TocGenerator(WordprocessingMLPackage wordMLPackage) throws TocException {
super(wordMLPackage);
this.wordMLPackage = wordMLPackage;
//获取父类的属性
try {
Method getTocStylesMethod = this.getClass().getSuperclass().getDeclaredMethod("getTocStyles", MainDocumentPart.class);
getTocStylesMethod.setAccessible(true);
tocStyles = (TocStyles) getTocStylesMethod.invoke(this, wordMLPackage.getMainDocumentPart());
}catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
@Override
protected SdtBlock generateToc(SdtBlock sdt, String instruction, STTabTlc leader, boolean skipPageNumbering) throws TocException {
MainDocumentPart documentPart = wordMLPackage.getMainDocumentPart();
SdtContentBlock sdtContent = (SdtContentBlock)sdt.getSdtContent();
if(sdtContent == null){
sdtContent = Context.getWmlObjectFactory().createSdtContentBlock();
sdt.setSdtContent(sdtContent);
}
try {
Method getTocStylesMethod = tocStyles.getClass().getDeclaredMethod("getStyleIdForName",String.class);
getTocStylesMethod.setAccessible(true);
String TOC_HEADING_STYLE = (String) getTocStylesMethod.invoke(tocStyles, TocStyles.TOC_HEADING);
if (TOC_HEADING_STYLE == null) {
String HEADING1_STYLE = (String) getTocStylesMethod.invoke(tocStyles, TocStyles.HEADING_1);
if (TOC_HEADING_STYLE == null) {
// We need to create it.
if (HEADING1_STYLE == null) {
Style style = (Style) XmlUtils.unmarshalString(XML_TOCHeading_BasedOn_Nothing);
style.getBasedOn().setVal(HEADING1_STYLE);
documentPart.getStyleDefinitionsPart().getContents().getStyle().add(style);
} else {
// There is a heading 1 style, so use a simple style based on that
Style style = (Style) XmlUtils.unmarshalString(XML_TOCHeading_BasedOn_Heading1);
style.getBasedOn().setVal(HEADING1_STYLE);
documentPart.getStyleDefinitionsPart().getContents().getStyle().add(style);
}
// either way,
TOC_HEADING_STYLE = "TOCHeading";
}
}
sdtContent.getContent().add(generateTocHeading(TOC_HEADING_STYLE,"目录"));
} catch (Exception e) {
throw new TocException(e.getMessage(),e);
}
populateToc(sdtContent, instruction, leader);
return sdt;
}
//添加目录标题
private static P generateTocHeading(String headingStyleId, String tocHeading) {
ObjectFactory wmlObjectFactory = Context.getWmlObjectFactory();
// Create object for p
P p = wmlObjectFactory.createP();
// Create object for pPr
PPr ppr = wmlObjectFactory.createPPr();
p.setPPr(ppr);
Jc jc = wmlObjectFactory.createJc();
jc.setVal(JcEnumeration.CENTER);
ppr.setJc(jc);
// Create object for pStyle
PPrBase.PStyle pprbasepstyle = wmlObjectFactory.createPPrBasePStyle();
ppr.setPStyle(pprbasepstyle);
pprbasepstyle.setVal(headingStyleId);
// Create object for r
R r = wmlObjectFactory.createR();
p.getContent().add(r);
// Create object for t (wrapped in JAXBElement)
Text text = wmlObjectFactory.createText();
JAXBElement<Text> textWrapped = wmlObjectFactory.createRT(text);
r.getContent().add(textWrapped);
text.setValue(tocHeading);
return p;
}
//填充目录内容
private void populateToc(
SdtContentBlock sdtContent,
String instruction, STTabTlc leader) throws TocException {
MainDocumentPart documentPart = wordMLPackage.getMainDocumentPart();
Document wmlDocumentEl = documentPart.getJaxbElement();
Body body = wmlDocumentEl.getBody();
// Generate new TOC
Toc toc = new Toc(instruction); // will throw an exception if it can't be parsed
// Process Toc switches
// .. we need page dimensions for right aligned tab (for page numbers)
// It is reasonable to require there to be a sectPr containing the necessary info
if (sectPr == null) {
// it doesn't fall back to the body level one
sectPr = this.wordMLPackage.getMainDocumentPart().getJaxbElement().getBody().getSectPr();
if (sectPr == null) {
throw new TocException("No sectPr following ToC");
}
}
PageDimensions pageDimensions = new PageDimensions(sectPr);
try {
pageDimensions.getWritableWidthTwips();
} catch (RuntimeException e) {
throw new TocException("margins or page width not defined in \n" + XmlUtils.marshaltoString(sectPr));
}
List<TocEntry> tocEntries = new ArrayList<TocEntry>();
@SuppressWarnings("unchecked")
List<P> pList = (List<P>)(List<?>) TocHelper.getAllElementsFromObject(body, P.class);
// Work out paragraph numbering
Map<P, Emulator.ResultTriple> pNumbersMap = numberParagraphs( pList);
SwitchProcessor sp = new SwitchProcessor(pageDimensions, leader);
tocEntries.addAll(
sp.processSwitches(wordMLPackage, pList, toc.getSwitches(), pNumbersMap));
if (tocEntries.size()==0) {
P p = new P();
p.getContent().addAll(toc.getTocInstruction());
sdtContent.getContent().add(p);
sdtContent.getContent().add(toc.getLastParagraph());
} else {
// Prep: merge instruction into first tocEntry (avoiding an unwanted additional paragraph)
P firstEntry = tocEntries.get(0).getEntryParagraph(tocStyles);
firstEntry.getContent().addAll(0, toc.getTocInstruction());
// Add Toc Entries paragraphs
for(TocEntry entry: tocEntries){
sdtContent.getContent().add(entry.getEntryParagraph(tocStyles));
}
// Add last toc paragraph
sdtContent.getContent().add(toc.getLastParagraph());
// // Add page numbers
// if(!skipPageNumbering && sp.pageNumbers() ) {
// for(TocEntry entry: tocEntries){
// entry.getEntryPageNumberText().setValue(Integer.toString((1)));
// }
// }
}
}
private Map<P, Emulator.ResultTriple> numberParagraphs(List<P> pList) {
org.docx4j.openpackaging.parts.WordprocessingML.NumberingDefinitionsPart numberingPart =
wordMLPackage.getMainDocumentPart().getNumberingDefinitionsPart();
Map<P, Emulator.ResultTriple> pNumbersMap = new HashMap<>();
if (numberingPart==null) {
return pNumbersMap;
}
numberingPart.getEmulator(true); // reset counters
for (P p : pList) {
if (p.getPPr()!=null) {
Emulator.ResultTriple triple = Emulator.getNumber(wordMLPackage, p.getPPr());
pNumbersMap.put(p, triple);
}
}
return pNumbersMap;
}
// Note these are only used if the style is not defined in the docx,
// nor in the default styles read by TocStyles.
private static String XML_TOCHeading_BasedOn_Nothing = "<w:style w:styleId=\"TOCHeading\" w:type=\"paragraph\" xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\">"
+ "<w:name w:val=\"TOC Heading\"/>"
// + "<w:basedOn w:val=\"Heading1\"/>" // would be ok if provided already present, since
+ "<w:next w:val=\"Normal\"/>"
+ "<w:uiPriority w:val=\"39\"/>"
+ "<w:semiHidden/>"
+ "<w:unhideWhenUsed/>"
+ "<w:qFormat/>"
+ "<w:pPr>"
+ "<w:keepNext/>"
+ "<w:keepLines/>"
+ "<w:spacing w:after=\"0\" w:before=\"480\"/>"
+ "<w:outlineLvl w:val=\"9\"/>"
+"</w:pPr>"
+ "<w:rPr>"
+ "<w:rFonts w:asciiTheme=\"majorHAnsi\" w:cstheme=\"majorBidi\" w:eastAsiaTheme=\"majorEastAsia\" w:hAnsiTheme=\"majorHAnsi\"/>"
+ "<w:b/>"
+ "<w:bCs/>"
+ "<w:color w:themeColor=\"accent1\" w:themeShade=\"BF\" w:val=\"365F91\"/>"
+ "<w:sz w:val=\"28\"/>"
+ "<w:szCs w:val=\"28\"/>"
+"</w:rPr>"
+"</w:style>";
private static String XML_TOCHeading_BasedOn_Heading1 = "<w:style w:styleId=\"TOCHeading\" w:type=\"paragraph\" xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\">"
+ "<w:name w:val=\"TOC Heading\"/>"
+ "<w:basedOn w:val=\"Heading1\"/>" // we'll overwrite with the style id
+ "<w:next w:val=\"Normal\"/>"
+ "<w:uiPriority w:val=\"39\"/>"
+ "<w:semiHidden/>"
+ "<w:unhideWhenUsed/>"
+ "<w:qFormat/>"
+ "<w:pPr>"
+ "<w:outlineLvl w:val=\"9\"/>"
+"</w:pPr>"
+"</w:style>";
}父接口
定义相关属性及方法
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.file.model.FileEntity;
import java.io.File;
import java.util.List;
/**
* @ClassName IFileConverter
* @Author wuzm
* @Date 2020/9/21 15:07
* @Version 1.0
*/
public interface IFileConverter {
/**
* 原文件类型
* @author wuzm
* @date 2020/9/21
*/
String sourceFileType();
/**
* 目标文件类型
* @author wuzm
* @date 2020/9/21
*/
String targetFileType();
/**
* 是否允许转换
* @author wuzm
* @date 2020/9/23
*/
boolean enableConvert();
/**
* 是否允许合并
* @author wuzm
* @date 2020/9/23
*/
boolean enableMerge();
/**
* 具体文件转换方法
* targetFileEntity中只包含部分转换后文件信息,
* 如name, spaceid, uploadid, mimetype, suffix, expiretime, accesstype, owner, createtime, updatetime
* @author wuzm
* @date 2020/9/21
*/
Result<List<File>> convert(FileEntity sourceFileEntity , FileEntity targetFileEntity) throws Exception;
/**
* 具体文件合并方法
* @param sourceFileEntity 需要合并的文件实体
* @param targetFileEntity 转换后文件部分信息
* @param targetFile 合并后的文件
* @return com.commnetsoft.commons.Result<java.lang.Void>
* @author wuzm
* @date 2020/9/23
*/
Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception;
}公共抽象类
提供获取文件输入流
java
import com.commnetsoft.file.model.FileEntity;
import com.commnetsoft.file.utils.FileHandlerFactory;
import com.commnetsoft.file.utils.IFileReadHandler;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
/**
* @ClassName AbstractFileConverter
* @Author wuzm
* @Date 2020/9/21 15:36
* @Version 1.0
*/
public abstract class AbstractFileConverter implements IFileConverter {
public final static String FILE_TYPE_TXT = "txt";
public final static String FILE_TYPE_DOC = "doc";
public final static String FILE_TYPE_DOCX = "docx";
public final static String FILE_TYPE_PDF = "pdf";
public final static String FILE_TYPE_ZIP = "zip";
public final static String FILE_TYPE_XLS = "xls";
public final static String FILE_TYPE_XLSX = "xlsx";
/**
* 获取文件输流
* @param sourceFileEntity 原文件对象
* @return java.io.InputStream
* @author wuzm
* @date 2020/9/22
*/
protected InputStream getFileInputStream(FileEntity sourceFileEntity) throws IOException {
URI newUri = URI.create(sourceFileEntity.getUrl());
IFileReadHandler fileReadHandler = FileHandlerFactory.getFileReadHandler(newUri.getScheme());
return fileReadHandler.readFile(sourceFileEntity.getUrl(), sourceFileEntity);
}
}各个类型转换类
Word类型
doc类型
抽象类
java
import com.commnetsoft.file.converter.AbstractFileConverter;
/**
* @ClassName AbstractWordConverter
* @Author wuzm
* @Date 2020/9/21 15:45
* @Version 1.0
*/
public abstract class AbstractDocConverter extends AbstractFileConverter {
@Override
public String sourceFileType() {
return "doc";
}
}转换各个类型实现类
转换为docx
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.file.converter.util.WordUtil;
import com.commnetsoft.file.converter.word.AbstractDocConverter;
import com.commnetsoft.file.model.FileEntity;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName DocToDocxConverter
* @Author wujs
* @Date 2020/9/24 16:38
* @Version 1.0
*/
@Component
public class DocToDocxConverter extends AbstractDocConverter {
@Override
public String targetFileType() {
return "docx";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = getFileInputStream(sourceFileEntity);
File file = WordUtil.wordConvert(inputStream, targetFileType());
if (null == file) {
return Result.create(CommonError.internal_error, "文件转换失败");
}
return Result.create(Arrays.asList(file));
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}转换为jpeg
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.file.converter.util.PictureUtil;
import com.commnetsoft.file.converter.word.AbstractDocConverter;
import com.commnetsoft.file.model.FileEntity;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName DocToJpegConverter
* @Author wujs
* @Date 2020/9/24 16:44
* @Version 1.0
*/
@Component
public class DocToJpegConverter extends AbstractDocConverter {
@Override
public String targetFileType() {
return "jpeg";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = getFileInputStream(sourceFileEntity);
File file = PictureUtil.wordToPictureByType(inputStream, targetFileType());
if (null == file) {
return Result.create(CommonError.internal_error, "doc文件转jpeg失败");
}
return Result.create(Arrays.asList(file));
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}转换为jpg
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.file.converter.util.PictureUtil;
import com.commnetsoft.file.converter.word.AbstractDocConverter;
import com.commnetsoft.file.model.FileEntity;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName DocToJpgConverter
* @Author wujs
* @Date 2020/9/24 16:44
* @Version 1.0
*/
@Component
public class DocToJpgConverter extends AbstractDocConverter {
@Override
public String targetFileType() {
return "jpg";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = getFileInputStream(sourceFileEntity);
File file = PictureUtil.wordToPictureByType(inputStream, targetFileType());
if (null == file) {
return Result.create(CommonError.internal_error, "doc文件转jpg失败");
}
return Result.create(Arrays.asList(file));
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}转换为pdf
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.file.converter.util.WordUtil;
import com.commnetsoft.file.converter.word.AbstractDocConverter;
import com.commnetsoft.file.model.FileEntity;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName DocToPdf
* @Author wujs
* @Date 2020/9/24 16:42
* @Version 1.0
*/
@Component
public class DocToPdfConverter extends AbstractDocConverter {
@Override
public String targetFileType() {
return "pdf";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = getFileInputStream(sourceFileEntity);
File file = WordUtil.wordConvert(inputStream, targetFileType());
if (null == file) {
return Result.create(CommonError.internal_error, "doc转pdf文件失败");
}
return Result.create(Arrays.asList(file));
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}转换为png
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.file.converter.util.PictureUtil;
import com.commnetsoft.file.converter.word.AbstractDocConverter;
import com.commnetsoft.file.model.FileEntity;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName DocToPngConverter
* @Author wujs
* @Date 2020/9/24 16:45
* @Version 1.0
*/
@Component
public class DocToPngConverter extends AbstractDocConverter {
@Override
public String targetFileType() {
return "png";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = getFileInputStream(sourceFileEntity);
File file = PictureUtil.wordToPictureByType(inputStream, targetFileType());
if (null == file) {
return Result.create(CommonError.internal_error, "doc文件转png失败");
}
return Result.create(Arrays.asList(file));
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}转换为txt类型
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.file.converter.util.WordUtil;
import com.commnetsoft.file.converter.word.AbstractDocConverter;
import com.commnetsoft.file.model.FileEntity;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName DocToTxtConverter
* @Author wujs
* @Date 2020/9/25 11:20
* @Version 1.0
*/
@Component
public class DocToTxtConverter extends AbstractDocConverter {
@Override
public String targetFileType() {
return "txt";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = getFileInputStream(sourceFileEntity);
File file = WordUtil.docToTxt(inputStream, targetFileType());
if (null == file) {
return Result.create(CommonError.internal_error, "文件转换失败");
}
return Result.create(Arrays.asList(file));
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}docx类型
抽象类
java
import com.commnetsoft.file.converter.AbstractFileConverter;
/**
* @ClassName AbstractDocxConverter
* @Author wujs
* @Date 2020/9/24 17:16
* @Version 1.0
*/
public abstract class AbstractDocxConverter extends AbstractFileConverter {
@Override
public String sourceFileType() {
return "docx";
}
}docx转换类
转换为doc
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.file.converter.util.WordUtil;
import com.commnetsoft.file.converter.word.AbstractDocxConverter;
import com.commnetsoft.file.model.FileEntity;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName DocxToDocConverter
* @Author wujs
* @Date 2020/9/24 16:24
* @Version 1.0
*/
@Component
public class DocxToDocConverter extends AbstractDocxConverter {
@Override
public String targetFileType() {
return "doc";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = getFileInputStream(sourceFileEntity);
File file = WordUtil.wordConvert(inputStream, targetFileType());
if (null == file) {
return Result.create(CommonError.internal_error, "docx转doc文件失败");
}
return Result.create(Arrays.asList(file));
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}转换为jpeg
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.file.converter.util.PictureUtil;
import com.commnetsoft.file.converter.word.AbstractDocxConverter;
import com.commnetsoft.file.model.FileEntity;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName DocxToJpegConverter
* @Author wujs
* @Date 2020/9/25 9:02
* @Version 1.0
*/
@Component
public class DocxToJpegConverter extends AbstractDocxConverter {
@Override
public String targetFileType() {
return "jpeg";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = getFileInputStream(sourceFileEntity);
File file = PictureUtil.wordToPictureByType(inputStream, targetFileType());
if (null == file) {
return Result.create(CommonError.internal_error, "docx文件转jpeg失败");
}
return Result.create(Arrays.asList(file));
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}转换为jpg类型
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.file.converter.util.PictureUtil;
import com.commnetsoft.file.converter.word.AbstractDocxConverter;
import com.commnetsoft.file.model.FileEntity;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName DocxToJpgConverter
* @Author wujs
* @Date 2020/9/25 9:02
* @Version 1.0
*/
@Component
public class DocxToJpgConverter extends AbstractDocxConverter {
@Override
public String targetFileType() {
return "jpg";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = getFileInputStream(sourceFileEntity);
File file = PictureUtil.wordToPictureByType(inputStream, targetFileType());
if (null == file) {
return Result.create(CommonError.internal_error, "docx文件转jpg失败");
}
return Result.create(Arrays.asList(file));
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}转换为pdf
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.file.converter.util.WordUtil;
import com.commnetsoft.file.converter.word.AbstractDocxConverter;
import com.commnetsoft.file.model.FileEntity;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName DocxToPdfConverter
* @Author wujs
* @Date 2020/9/24 9:20
* @Version 1.0
*/
@Component
public class DocxToPdfConverter extends AbstractDocxConverter {
@Override
public String targetFileType() {
return "pdf";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = getFileInputStream(sourceFileEntity);
File file = WordUtil.wordConvert(inputStream, targetFileType());
if (null == file) {
return Result.create(CommonError.internal_error, "docx转pdf文件失败");
}
return Result.create(Arrays.asList(file));
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}转换为png
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.file.converter.util.PictureUtil;
import com.commnetsoft.file.converter.word.AbstractDocxConverter;
import com.commnetsoft.file.model.FileEntity;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName DocxToJpgConverter
* @Author wujs
* @Date 2020/9/25 9:03
* @Version 1.0
*/
@Component
public class DocxToPngConverter extends AbstractDocxConverter {
@Override
public String targetFileType() {
return "png";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = getFileInputStream(sourceFileEntity);
File file = PictureUtil.wordToPictureByType(inputStream, targetFileType());
if (null == file) {
return Result.create(CommonError.internal_error, "docx文件转png失败");
}
return Result.create(Arrays.asList(file));
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}转换为txt
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.file.converter.util.WordUtil;
import com.commnetsoft.file.converter.word.AbstractDocxConverter;
import com.commnetsoft.file.model.FileEntity;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName DocxToTxtConverter
* @Author wujs
* @Date 2020/9/25 13:49
* @Version 1.0
*/
@Component
public class DocxToTxtConverter extends AbstractDocxConverter {
@Override
public String targetFileType() {
return "txt";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = getFileInputStream(sourceFileEntity);
File file = WordUtil.docxToTxt(inputStream, targetFileType());
if (null == file) {
return Result.create(CommonError.internal_error, "文件转换失败");
}
return Result.create(Arrays.asList(file));
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}Txt类型
抽象类
java
import com.commnetsoft.file.converter.AbstractFileConverter;
/**
* @ClassName AbstractTxtConverter
* @Author wujs
* @Date 2020/9/25 9:53
* @Version 1.0
*/
public abstract class AbstractTxtConverter extends AbstractFileConverter {
@Override
public String sourceFileType() {
return "txt";
}
}转doc
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.file.converter.util.WordUtil;
import com.commnetsoft.file.model.FileEntity;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName TxtToDocConverter
* @Author wujs
* @Date 2020/9/25 9:55
* @Version 1.0
*/
@Component
public class TxtToDocConverter extends AbstractTxtConverter {
@Override
public String targetFileType() {
return "doc";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = getFileInputStream(sourceFileEntity);
File file = WordUtil.txtToWordByType(inputStream, targetFileType());
if (null == file) {
return Result.create(CommonError.internal_error, "txt转doc失败");
}
return Result.create(Arrays.asList(file));
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}转docx
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.file.converter.util.WordUtil;
import com.commnetsoft.file.model.FileEntity;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName TxtToDocxConverter
* @Author wujs
* @Date 2020/9/25 9:55
* @Version 1.0
*/
@Component
public class TxtToDocxConverter extends AbstractTxtConverter{
@Override
public String targetFileType() {
return "docx";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = getFileInputStream(sourceFileEntity);
File file = WordUtil.txtToWordByType(inputStream, targetFileType());
if (null == file) {
return Result.create(CommonError.internal_error, "txt转doc失败");
}
return Result.create(Arrays.asList(file));
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}转pdf
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.file.converter.util.PdfUtil;
import com.commnetsoft.file.model.FileEntity;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName TxtToPdfConverter
* @Author wujs
* @Date 2020/9/28 9:38
* @Version 1.0
*/
@Component
public class TxtToPdfConverter extends AbstractTxtConverter {
@Override
public String targetFileType() {
return "pdf";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = getFileInputStream(sourceFileEntity);
File file = PdfUtil.txtToPdf(inputStream, targetFileType());
if (null == file) {
return Result.create(CommonError.internal_error, "txt转pdf失败");
}
return Result.create(Arrays.asList(file));
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}Picture类型
jpeg类型
父抽象类
java
import com.commnetsoft.file.converter.AbstractFileConverter;
/**
* @ClassName AbstractJpegConverter
* @Author wujs
* @Date 2020/9/25 9:26
* @Version 1.0
*/
public abstract class AbstractJpegConverter extends AbstractFileConverter {
@Override
public String sourceFileType() {
return "jpeg";
}
}转jpg
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.file.converter.picture.AbstractJpegConverter;
import com.commnetsoft.file.converter.util.PictureUtil;
import com.commnetsoft.file.model.FileEntity;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName JpegToJpgConverter
* @Author wujs
* @Date 2020/9/25 9:38
* @Version 1.0
*/
@Component
public class JpegToJpgConverter extends AbstractJpegConverter {
@Override
public String targetFileType() {
return "jpg";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = getFileInputStream(sourceFileEntity);
File file = PictureUtil.pictureConvertByType(inputStream, targetFileType(),sourceFileType());
if (null == file) {
return Result.create(CommonError.internal_error, "jpeg转jpg失败");
}
return Result.create(Arrays.asList(file));
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}转pdf
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.file.converter.picture.AbstractJpegConverter;
import com.commnetsoft.file.converter.util.PictureUtil;
import com.commnetsoft.file.model.FileEntity;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName JpegToPdfConverter
* @Author wujs
* @Date 2020/9/25 9:23
* @Version 1.0
*/
@Component
public class JpegToPdfConverter extends AbstractJpegConverter {
@Override
public String targetFileType() {
return "pdf";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = getFileInputStream(sourceFileEntity);
File file = PictureUtil.pictureToPdf(inputStream,targetFileType());
if (null == file){
return Result.create(CommonError.internal_error,"jpeg转pdf失败");
}
return Result.create(Arrays.asList(file));
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}转png
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.file.converter.picture.AbstractJpegConverter;
import com.commnetsoft.file.converter.util.PictureUtil;
import com.commnetsoft.file.model.FileEntity;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName JpegToPngConverter
* @Author wujs
* @Date 2020/9/25 9:43
* @Version 1.0
*/
@Component
public class JpegToPngConverter extends AbstractJpegConverter {
@Override
public String targetFileType() {
return "png";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = getFileInputStream(sourceFileEntity);
File file = PictureUtil.pictureConvertByType(inputStream, targetFileType(),sourceFileType());
if (null == file) {
return Result.create(CommonError.internal_error, "jpeg转jpg失败");
}
return Result.create(Arrays.asList(file));
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}jpg类型
父抽象类
java
import com.commnetsoft.file.converter.AbstractFileConverter;
/**
* @ClassName AbstractJpgConverter
* @Author wujs
* @Date 2020/9/25 9:25
* @Version 1.0
*/
public abstract class AbstractJpgConverter extends AbstractFileConverter {
@Override
public String sourceFileType() {
return "jpg";
}
}转jpeg
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.file.converter.picture.AbstractJpgConverter;
import com.commnetsoft.file.converter.util.PictureUtil;
import com.commnetsoft.file.model.FileEntity;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName JpgToJpegConverter
* @Author wujs
* @Date 2020/9/25 9:45
* @Version 1.0
*/
@Component
public class JpgToJpegConverter extends AbstractJpgConverter {
@Override
public String targetFileType() {
return "jpeg";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = getFileInputStream(sourceFileEntity);
File file = PictureUtil.pictureConvertByType(inputStream, targetFileType(),sourceFileType());
if (null == file) {
return Result.create(CommonError.internal_error, "jpg转jpeg失败");
}
return Result.create(Arrays.asList(file));
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}转pdf
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.file.converter.picture.AbstractJpgConverter;
import com.commnetsoft.file.converter.util.PictureUtil;
import com.commnetsoft.file.model.FileEntity;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName JpgToPdfConverter
* @Author wujs
* @Date 2020/9/25 9:22
* @Version 1.0
*/
@Component
public class JpgToPdfConverter extends AbstractJpgConverter {
@Override
public String targetFileType() {
return "pdf";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = getFileInputStream(sourceFileEntity);
File file = PictureUtil.pictureToPdf(inputStream,targetFileType());
if (null == file){
return Result.create(CommonError.internal_error,"jpeg转pdf失败");
}
return Result.create(Arrays.asList(file));
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}转png
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.file.converter.picture.AbstractJpgConverter;
import com.commnetsoft.file.converter.util.PictureUtil;
import com.commnetsoft.file.model.FileEntity;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName JpgToPngConverter
* @Author wujs
* @Date 2020/9/25 9:45
* @Version 1.0
*/
@Component
public class JpgToPngConverter extends AbstractJpgConverter {
@Override
public String targetFileType() {
return "png";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = getFileInputStream(sourceFileEntity);
File file = PictureUtil.pictureConvertByType(inputStream, targetFileType(),sourceFileType());
if (null == file) {
return Result.create(CommonError.internal_error, "jpeg转jpg失败");
}
return Result.create(Arrays.asList(file));
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}png类型
父抽象类
java
import com.commnetsoft.file.converter.AbstractFileConverter;
/**
* @ClassName AbstractPngConverter
* @Author wujs
* @Date 2020/9/25 9:27
* @Version 1.0
*/
public abstract class AbstractPngConverter extends AbstractFileConverter {
@Override
public String sourceFileType() {
return "png";
}
}转jpeg
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.file.converter.picture.AbstractPngConverter;
import com.commnetsoft.file.converter.util.PictureUtil;
import com.commnetsoft.file.model.FileEntity;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName PngToJpegConverter
* @Author wujs
* @Date 2020/9/25 9:46
* @Version 1.0
*/
@Component
public class PngToJpegConverter extends AbstractPngConverter {
@Override
public String targetFileType() {
return "jpeg";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = getFileInputStream(sourceFileEntity);
File file = PictureUtil.pictureConvertByType(inputStream, targetFileType(),sourceFileType());
if (null == file) {
return Result.create(CommonError.internal_error, "jpeg转jpg失败");
}
return Result.create(Arrays.asList(file));
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}转jpg
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.file.converter.picture.AbstractPngConverter;
import com.commnetsoft.file.converter.util.PictureUtil;
import com.commnetsoft.file.model.FileEntity;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName PngToJpgConverter
* @Author wujs
* @Date 2020/9/25 9:46
* @Version 1.0
*/
@Component
public class PngToJpgConverter extends AbstractPngConverter {
@Override
public String targetFileType() {
return "jpg";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = getFileInputStream(sourceFileEntity);
File file = PictureUtil.pictureConvertByType(inputStream, targetFileType(),sourceFileType());
if (null == file) {
return Result.create(CommonError.internal_error, "jpeg转jpg失败");
}
return Result.create(Arrays.asList(file));
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}转pdf
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.file.converter.picture.AbstractPngConverter;
import com.commnetsoft.file.converter.util.PictureUtil;
import com.commnetsoft.file.model.FileEntity;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName PngToPdfConverter
* @Author wujs
* @Date 2020/9/25 9:24
* @Version 1.0
*/
@Component
public class PngToPdfConverter extends AbstractPngConverter {
@Override
public String targetFileType() {
return "pdf";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = getFileInputStream(sourceFileEntity);
File file = PictureUtil.pictureToPdf(inputStream,targetFileType());
if (null == file) {
return Result.create(CommonError.internal_error, "jpeg转pdf失败");
}
return Result.create(Arrays.asList(file));
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}Pdf类型
父抽象类
java
import com.commnetsoft.file.converter.AbstractFileConverter;
/**
* @ClassName AbstractPdfConverter
* @Author wuzm
* @Date 2020/9/21 15:35
* @Version 1.0
*/
public abstract class AbstractPdfConverter extends AbstractFileConverter {
@Override
public String sourceFileType() {
return "pdf";
}
}转换为doc
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.file.converter.util.PdfUtil;
import com.commnetsoft.file.model.FileEntity;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName PdfToDocConverter
* @Author wujs
* @Date 2020/9/24 15:50
* @Version 1.0
*/
@Component
public class PdfToDocConverter extends AbstractPdfConverter{
@Override
public String targetFileType() {
return "doc";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = getFileInputStream(sourceFileEntity);
File file = PdfUtil.pdfToWord(inputStream, targetFileType());
if (null == file) {
return Result.create(CommonError.internal_error, "文件转换失败");
}
return Result.create(Arrays.asList(file));
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}转换为docx
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.file.converter.util.PdfUtil;
import com.commnetsoft.file.model.FileEntity;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName PdfToDocxConverter
* @Author wujs
* @Date 2020/9/24 16:00
* @Version 1.0
*/
@Component
public class PdfToDocxConverter extends AbstractPdfConverter {
@Override
public String targetFileType() {
return "docx";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = getFileInputStream(sourceFileEntity);
File file = PdfUtil.pdfToWord(inputStream, targetFileType());
if (null == file) {
return Result.create(CommonError.internal_error, "文件转换失败");
}
return Result.create(Arrays.asList(file));
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}转换为jpeg
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.file.converter.util.PictureUtil;
import com.commnetsoft.file.model.FileEntity;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName PdfToJpegConverter
* @Author wujs
* @Date 2020/9/24 16:05
* @Version 1.0
*/
@Component
public class PdfToJpegConverter extends AbstractPdfConverter {
@Override
public String targetFileType() {
return "jpeg";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = getFileInputStream(sourceFileEntity);
File file = PictureUtil.pdfToPictureByType(inputStream, targetFileType());
if (null == file) {
return Result.create(CommonError.internal_error, "文件转换失败");
}
return Result.create(Arrays.asList(file));
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}转换为jpg
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.file.converter.util.PictureUtil;
import com.commnetsoft.file.model.FileEntity;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName PdfToJpgConverter
* @Author wujs
* @Date 2020/9/24 16:04
* @Version 1.0
*/
@Component
public class PdfToJpgConverter extends AbstractPdfConverter {
@Override
public String targetFileType() {
return "jpg";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = getFileInputStream(sourceFileEntity);
File file = PictureUtil.pdfToPictureByType(inputStream, targetFileType());
if (null == file) {
return Result.create(CommonError.internal_error, "文件转换失败");
}
return Result.create(Arrays.asList(file));
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}转换为png
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.file.converter.util.PictureUtil;
import com.commnetsoft.file.model.FileEntity;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName PdfToPngConverter
* @Author wujs
* @Date 2020/9/24 16:06
* @Version 1.0
*/
@Component
public class PdfToPngConverter extends AbstractPdfConverter {
@Override
public String targetFileType() {
return "png";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = getFileInputStream(sourceFileEntity);
File file = PictureUtil.pdfToPictureByType(inputStream, targetFileType());
if (null == file) {
return Result.create(CommonError.internal_error, "文件转换失败");
}
return Result.create(Arrays.asList(file));
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}转换为txt
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.commons.utils.UUIDUtils;
import com.commnetsoft.file.model.FileEntity;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;
import org.springframework.stereotype.Component;
import java.io.*;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName PdfToTxtConverter
* @Author wuzm
* @Date 2020/9/21 15:35
* @Version 1.0
*/
@Component
public class PdfToTxtConverter extends AbstractPdfConverter {
@Override
public String targetFileType() {
return "txt";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = null;
Writer writer = null;
PDDocument pdDocument = null;
try {
inputStream = getFileInputStream(sourceFileEntity);
File tempDirPath = new File(System.getProperty("java.io.tmpdir"));
File txtFile = new File(tempDirPath, UUIDUtils.generate() + "." + targetFileType());
writer = new OutputStreamWriter(new FileOutputStream(txtFile), "UTF-8");
pdDocument = PDDocument.load(inputStream);
PDFTextStripper pdfTextStripper = new PDFTextStripper();
pdfTextStripper.writeText(pdDocument, writer);
return Result.create(Arrays.asList(txtFile));
} finally {
if(null != inputStream) inputStream.close();
if (null != writer) writer.close();
if (null != pdDocument) pdDocument.close();
}
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}Html类型
父抽象类
java
import com.commnetsoft.file.converter.AbstractFileConverter;
import org.springframework.stereotype.Component;
/**
* @ClassName AbstractHtmlConverter
* @Author wujs
* @Date 2021/1/28 14:54
* @Version 1.0
*/
@Component
public abstract class AbstractHtmlConverter extends AbstractFileConverter {
@Override
public String sourceFileType() {
return "html";
}
}转docx
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.file.converter.util.PdfUtil;
import com.commnetsoft.file.model.FileEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName HtmlTodocxConverter
* @Author wujs
* @Date 2021/1/28 15:05
* @Version 1.0
*/
@Component
public class HtmlTodocxConverter extends AbstractHtmlConverter {
@Autowired
private PdfUtil pdfUtil;
@Override
public String targetFileType() {
return "docx";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = getFileInputStream(sourceFileEntity);
return Result.create(Arrays.asList(pdfUtil.convert(inputStream,targetFileType())));
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}转pdf
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.file.converter.util.PdfUtil;
import com.commnetsoft.file.model.FileEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName HtmlToPdfConverter
* @Author wujs
* @Date 2021/1/28 14:55
* @Version 1.0
*/
@Component
public class HtmlToPdfConverter extends AbstractHtmlConverter {
@Autowired
private PdfUtil pdfUtil;
@Override
public String targetFileType() {
return "pdf";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = getFileInputStream(sourceFileEntity);
return Result.create(Arrays.asList(pdfUtil.convert(inputStream,targetFileType())));
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}Excel类型
xls类型
父抽象类
java
import com.commnetsoft.file.converter.AbstractFileConverter;
/**
* @ClassName AbstractExcelConverter
* @Author wujs
* @Date 2020/9/24 9:21
* @Version 1.0
*/
public abstract class AbstractXlsConverter extends AbstractFileConverter {
@Override
public String sourceFileType() {
return "xls";
}
}转换为doc
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.file.converter.excel.AbstractXlsConverter;
import com.commnetsoft.file.converter.util.ExcelUtil;
import com.commnetsoft.file.model.FileEntity;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName XlsToDocConverter
* @Author wujs
* @Date 2020/9/27 9:59
* @Version 1.0
*/
@Component
public class XlsToDocConverter extends AbstractXlsConverter {
@Override
public String targetFileType() {
return "doc";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = getFileInputStream(sourceFileEntity);
File xlsToDocx = ExcelUtil.excelToWord(inputStream, targetFileType(),sourceFileType());
if (null == xlsToDocx) {
return Result.create(CommonError.internal_error, "xls转doc失败!");
}
return Result.create(Arrays.asList(xlsToDocx));
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}转换为docx
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.file.converter.excel.AbstractXlsConverter;
import com.commnetsoft.file.converter.util.ExcelUtil;
import com.commnetsoft.file.model.FileEntity;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName XlsToDocConverter
* @Author wujs
* @Date 2020/9/27 10:00
* @Version 1.0
*/
@Component
public class XlsToDocxConverter extends AbstractXlsConverter {
@Override
public String targetFileType() {
return "docx";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = getFileInputStream(sourceFileEntity);
File xlsToDocx = ExcelUtil.excelToWord(inputStream, targetFileType(),sourceFileType());
if (null == xlsToDocx) {
return Result.create(CommonError.internal_error, "xls转docx失败!");
}
return Result.create(Arrays.asList(xlsToDocx));
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}转换为pdf
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.file.converter.excel.AbstractXlsConverter;
import com.commnetsoft.file.converter.util.ExcelUtil;
import com.commnetsoft.file.model.FileEntity;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName XlsToPdfConverter
* @Author wujs
* @Date 2020/9/27 10:51
* @Version 1.0
*/
@Component
public class XlsToPdfConverter extends AbstractXlsConverter {
@Override
public String targetFileType() {
return "pdf";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = getFileInputStream(sourceFileEntity);
File file = ExcelUtil.excelTopdf(inputStream, targetFileType(),sourceFileType());
if (null == file) {
return Result.create(CommonError.internal_error, "xls转pdf失败");
}
return Result.create(Arrays.asList(file));
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}转换为txt
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.file.converter.excel.AbstractXlsConverter;
import com.commnetsoft.file.converter.util.ExcelUtil;
import com.commnetsoft.file.model.FileEntity;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName ExcelToTxtConverter
* @Author wujs
* @Date 2020/9/25 9:25
* @Version 1.0
*/
@Component
public class XlsToTxtConverter extends AbstractXlsConverter {
@Override
public String targetFileType() {
return "txt";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = getFileInputStream(sourceFileEntity);
File file = ExcelUtil.excelToTxt(inputStream, targetFileType(),sourceFileType());
if (null == file) {
return Result.create(CommonError.internal_error, "文件转换失败");
}
return Result.create(Arrays.asList(file));
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}xlsx类型
父抽象类
java
import com.commnetsoft.file.converter.AbstractFileConverter;
/**
* @ClassName AbstractXlsxConverter
* @Author wujs
* @Date 2020/9/25 9:51
* @Version 1.0
*/
public abstract class AbstractXlsxConverter extends AbstractFileConverter {
@Override
public String sourceFileType() {
return "xlsx";
}
}转换为doc
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.file.converter.excel.AbstractXlsxConverter;
import com.commnetsoft.file.converter.util.ExcelUtil;
import com.commnetsoft.file.model.FileEntity;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.util.Collections;
import java.util.List;
/**
* @ClassName XlsxToDocConverter
* @Author wujs
* @Date 2020/927 10:00
* @Version 1.0
*/
@Component
public class XlsxToDocConverter extends AbstractXlsxConverter {
@Override
public String targetFileType() {
return "doc";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = getFileInputStream(sourceFileEntity);
File xlsToDocx = ExcelUtil.excelToWord(inputStream, targetFileType(),sourceFileType());
if (null == xlsToDocx) {
return Result.create(CommonError.internal_error, "xlsx转doc失败!");
}
return Result.create(Collections.singletonList(xlsToDocx));
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}转换为docx
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.file.converter.excel.AbstractXlsxConverter;
import com.commnetsoft.file.converter.util.ExcelUtil;
import com.commnetsoft.file.model.FileEntity;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName XlsxToDocxConverter
* @Author wujs
* @Date 2020/927 10:00
* @Version 1.0
*/
@Component
public class XlsxToDocxConverter extends AbstractXlsxConverter {
@Override
public String targetFileType() {
return "docx";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = getFileInputStream(sourceFileEntity);
File xlsToDocx = ExcelUtil.excelToWord(inputStream, targetFileType(), sourceFileType());
if (null == xlsToDocx) {
return Result.create(CommonError.internal_error, "xlsx转doc失败!");
}
return Result.create(Arrays.asList(xlsToDocx));
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}转换为pdf
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.file.converter.excel.AbstractXlsxConverter;
import com.commnetsoft.file.converter.util.ExcelUtil;
import com.commnetsoft.file.model.FileEntity;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName XlsxToPdfConverter
* @Author wujs
* @Date 2020/9/27 17:27
* @Version 1.0
*/
@Component
public class XlsxToPdfConverter extends AbstractXlsxConverter {
@Override
public String targetFileType() {
return "pdf";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = getFileInputStream(sourceFileEntity);
File file = ExcelUtil.excelTopdf(inputStream, targetFileType(), sourceFileType());
if (null == file) {
return Result.create(CommonError.internal_error, "xlsx转pdf失败");
}
return Result.create(Arrays.asList(file));
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}转换为txt
java
import com.commnetsoft.commons.Result;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.file.converter.excel.AbstractXlsxConverter;
import com.commnetsoft.file.converter.util.ExcelUtil;
import com.commnetsoft.file.model.FileEntity;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName XlsxToTxtConverter
* @Author wujs
* @Date 2020/9/25 10:48
* @Version 1.0
*/
@Component
public class XlsxToTxtConverter extends AbstractXlsxConverter {
@Override
public String targetFileType() {
return "txt";
}
@Override
public boolean enableConvert() {
return true;
}
@Override
public boolean enableMerge() {
return false;
}
@Override
public Result<List<File>> convert(FileEntity sourceFileEntity, FileEntity targetFileEntity) throws Exception {
InputStream inputStream = getFileInputStream(sourceFileEntity);
File file = ExcelUtil.excelToTxt(inputStream, targetFileType(),sourceFileType());
if (null == file) {
return Result.create(CommonError.internal_error, "文件转换失败");
}
return Result.create(Arrays.asList(file));
}
@Override
public Result<Void> merge(FileEntity sourceFileEntity, FileEntity targetFileEntity, File targetFile) throws Exception {
return null;
}
}