2021SC@SDUSC
目录
消费队列中的转换文件FileConvertQueueTask
消费队列中的转换文件FileConvertQueueTask
FileConvertQueueTask是该项目层中的业务组件,因为其被@service注解标记。
1、初始化方法:
初始类中的previewFactory、cacheservice和filehandlerservice对象。
public FileConvertQueueTask(FilePreviewFactory previewFactory, CacheService cacheService, FileHandlerService fileHandlerService) {
this.previewFactory = previewFactory;
this.cacheService = cacheService;
this.fileHandlerService = fileHandlerService;
}
2、startTask方法:开启队列
@PostConstruct是Java自己的注解,被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次。PostConstruct在构造函数之后执行。
在这个方法中,启动线程,在线程里实例化一个ConverterTask存放处理文件转换的队列,这样全局的转换文件就可以存放到队列中。队列中包含的对象有previewFactory、cacheService、fileHandlerService。
@PostConstruct
public void startTask() {
new Thread(new ConvertTask(previewFactory, cacheService, fileHandlerService))
.start();
logger.info("队列处理文件转换任务启动完成 ");
}
ConverterTask类
static class ConvertTask implements Runnable {
private final Logger logger = LoggerFactory.getLogger(ConvertTask.class);
private final FilePreviewFactory previewFactory;
private final CacheService cacheService;
private final FileHandlerService fileHandlerService;
public ConvertTask(FilePreviewFactory previewFactory,
CacheService cacheService,
FileHandlerService fileHandlerService) {
this.previewFactory = previewFactory;
this.cacheService = cacheService;
this.fileHandlerService = fileHandlerService;
}
3、队列运行分析
当队列中存入url时,首先分析要转换文件的初始类型,之后才可以选择合适的处理方法。首先实例化FileAttribute对象fileAttribute,通过调用fileHandlerService的方法getFileAttribute(url, null)获取;实例化 FileType 对象fileType,通过调用fileAttribute的getType()方法,这样获取文件类型就完成。(FileAttribute的方法在之前有分析。)
之后通过调用isNeedConvert(fileType)分析文件是否需要转换,如果需要处理调用 FilePreview对象filePreview,该对象通过调用previewFactory.get(fileAttribute)方法获取,之后调用filePreview.filePreviewHandle(url, new ExtendedModelMap(), fileAttribute)方法对预制文件进行处理。
如果中途线程出现问题,先尝试Sleep,如果sleep出现异常,中断当前线程并报错。
@Override
public void run() {
while (true) {
String url = null;
try {
url = cacheService.takeQueueTask();
if (url != null) {
FileAttribute fileAttribute = fileHandlerService.getFileAttribute(url, null);
FileType fileType = fileAttribute.getType();
logger.info("正在处理预览转换任务,url:{},预览类型:{}", url, fileType);
if (isNeedConvert(fileType)) {
FilePreview filePreview = previewFactory.get(fileAttribute);
filePreview.filePreviewHandle(url, new ExtendedModelMap(), fileAttribute);
} else {
logger.info("预览类型无需处理,url:{},预览类型:{}", url, fileType);
}
}
} catch (Exception e) {
try {
TimeUnit.SECONDS.sleep(10);
} catch (Exception ex) {
Thread.currentThread().interrupt();
ex.printStackTrace();
}
logger.info("处理预览转换任务异常,url:{}", url, e);
}
}
}
4、判断是否需要转换
如果filetype中含有"compress"、"office"、"cad"这三个字符串,则判定是需要处理的文件,将true传回给调用函数,之后即可用FilePreview进行处理。
public boolean isNeedConvert(FileType fileType) {
return fileType.equals(FileType.COMPRESS) ||
fileType.equals(FileType.OFFICE) ||
fileType.equals(FileType.CAD);
}
文件处理服务类FileHandlerService
这个类之前在介绍pdf文件转换的时候有提到,这里面有pdf转图片的方法,也有cad文件转pdf的方法。但是这个类中封装了一些在文件转换中重复度比较高的代码,比如存放文件缓存、获取文件路径、转换路径等相关问题。在下文将进行详细介绍。
1、获取已经转换过的文件集合
由于文件类型不贴心,获取文件缓存的方式也不同。主要有以下几种:
一种是调用cacheService的getPDFCache获取转换过的pdf文件缓存
/**
* @return 已转换过的文件集合(缓存)
*/
public Map<String, String> listConvertedFiles() {
return cacheService.getPDFCache();
}
一种是 根据文件名获取文件集合
/**
* @return 已转换过的文件,根据文件名获取
*/
public String getConvertedFile(String key) {
return cacheService.getPDFCache(key);
}
获取视频文件集合
/**
* @return 已转换过的视频文件集合(缓存)
*/
public Map<String, String> listConvertedMedias() {
return cacheService.getMediaConvertCache();
}
/**
* 添加转换后的视频文件缓存
* @param fileName
* @param value
*/
public void addConvertedMedias(String fileName, String value) {
cacheService.putMediaConvertCache(fileName, value);
}
/**
* @return 已转换视频文件缓存,根据文件名获取
*/
public String getConvertedMedias(String key) {
return cacheService.getMediaConvertCache(key);
}
2、路径转换
调用cacheService的getPdfImageCache方法,根据pdf本地路径转换成生成图片的本地相对路径,该方法在pdf2jpg中有调用。
/**
* @param key pdf本地路径
* @return 已将pdf转换成图片的图片本地相对路径
*/
public Integer getConvertedPdfImage(String key) {
return cacheService.getPdfImageCache(key);
}
3、路径提取
通过分割路径path的字符串获取文件名。
/**
* 从路径中获取文件名
*
* @param path 类似这种:C:\Users\yudian-it\Downloads
* @return 文件名
*/
public String getFileNameFromPath(String path) {
return path.substring(path.lastIndexOf(File.separator) + 1);
}
绝对路径->相对路径
通过对绝对路径字符串分割获取相对路径
/**
* 获取相对路径
*
* @param absolutePath 绝对路径
* @return 相对路径
*/
public String getRelativePath(String absolutePath) {
return absolutePath.substring(fileDir.length());
}
4、解压压缩包图片文件
调用cacheservice的方法getImgCache,获取图片 以及putImgCache将图片添加至压缩包。
/**
* 获取redis中压缩包内图片文件
*
* @param fileKey fileKey
* @return 图片文件访问url列表
*/
public List<String> getImgCache(String fileKey) {
return cacheService.getImgCache(fileKey);
}
/**
* 设置redis中压缩包内图片文件
*
* @param fileKey fileKey
* @param imgs 图片文件访问url列表
*/
public void putImgCache(String fileKey, List<String> imgs) {
cacheService.putImgCache(fileKey, imgs);
}
5、添加缓存
根据缓存的类型不同分为pdf缓存和pdf图片缓存。
/**
* 添加转换后PDF缓存
*
* @param fileName pdf文件名
* @param value 缓存相对路径
*/
public void addConvertedFile(String fileName, String value) {
cacheService.putPDFCache(fileName, value);
}
/**
* 添加转换后图片组缓存
*
* @param pdfFilePath pdf文件绝对路径
* @param num 图片张数
*/
public void addConvertedPdfImage(String pdfFilePath, int num) {
cacheService.putPdfImageCache(pdfFilePath, num);
}
6、对转换后的文件进行操作
这个方法主要用于改变编码格式,首先声明对象StringBuilder,之后选择编码方式gb2312或者是utf-8,之后添加sheet控制头。全部完成之后生成FileOutputStream文件输出流,将文件都写入参数outfilepath中。
public void doActionConvertedFile(String outFilePath) {
StringBuilder sb = new StringBuilder();
try (InputStream inputStream = new FileInputStream(outFilePath);
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, DEFAULT_CONVERTER_CHARSET))) {
String line;
while (null != (line = reader.readLine())) {
if (line.contains("charset=gb2312")) {
line = line.replace("charset=gb2312", "charset=utf-8");
}
sb.append(line);
}
// 添加sheet控制头
sb.append("<script src=\"js/jquery-3.0.0.min.js\" type=\"text/javascript\"></script>");
sb.append("<script src=\"js/excel.header.js\" type=\"text/javascript\"></script>");
sb.append("<link rel=\"stylesheet\" href=\"bootstrap/css/bootstrap.min.css\">");
} catch (IOException e) {
e.printStackTrace();
}
// 重新写入文件
try (FileOutputStream fos = new FileOutputStream(outFilePath);
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fos, StandardCharsets.UTF_8))) {
writer.write(sb.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
7、获取文件属性
public FileAttribute getFileAttribute(String url, HttpServletRequest req) {
FileAttribute attribute = new FileAttribute();
String suffix;
FileType type;
String fileName;
String fullFileName = WebUtils.getUrlParameterReg(url, "fullfilename");
if (StringUtils.hasText(fullFileName)) {
fileName = fullFileName;
type = FileType.typeFromFileName(fullFileName);
suffix = KkFileUtils.suffixFromFileName(fullFileName);
} else {
fileName = WebUtils.getFileNameFromURL(url);
type = FileType.typeFromUrl(url);
suffix = WebUtils.suffixFromUrl(url);
}
attribute.setType(type);
attribute.setName(fileName);
attribute.setSuffix(suffix);
attribute.setUrl(url);
if (req != null) {
String officePreviewType = req.getParameter("officePreviewType");
String fileKey = WebUtils.getUrlParameterReg(url,"fileKey");
if (StringUtils.hasText(officePreviewType)) {
attribute.setOfficePreviewType(officePreviewType);
}
if (StringUtils.hasText(fileKey)) {
attribute.setFileKey(fileKey);
}
}
return attribute;
}