com.houkunlin.system.common.aop.DownloadFileAspect Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of system-common-aop-starter Show documentation
Show all versions of system-common-aop-starter Show documentation
常用的 AOP 注解功能。
Commonly used AOP annotation features.
The newest version!
package com.houkunlin.system.common.aop;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.io.Resource;
import org.springframework.util.ObjectUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.function.Supplier;
/**
* 文件下载
*
* @author HouKunLin
* @see DownloadFile
*/
@Slf4j
@Aspect
@RequiredArgsConstructor
public class DownloadFileAspect {
private final TemplateParser templateParser;
private final DownloadFileHandler downloadFileHandler;
private final HttpServletRequest request;
private final HttpServletResponse response;
public static final String unknownFilename = "未知文件.unknown";
public static final String ERROR_TEXT = "文件下载失败,此文件可能从服务器丢失,请联系管理员核查。文件信息:";
public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
@Around("@annotation(annotation)")
public Object doAround(ProceedingJoinPoint pjp, DownloadFile annotation) throws Throwable {
try {
Object object = pjp.proceed();
List list;
if (object == null) {
if (annotation.source().isBlank()) {
list = Collections.emptyList();
} else {
list = getFileOutputs(null, annotation.source(), false);
}
} else {
list = getFileOutputs(null, object, false);
}
if (list.isEmpty()) {
writeEmpty(pjp, annotation, object);
} else if (list.size() == 1 && !annotation.forceCompress()) {
writeOne(pjp, annotation, object, list.get(0));
} else {
writeZip(pjp, annotation, object, list);
}
return null;
} catch (Throwable e) {
log.error("下载文件失败,发生了异常:{}", e.getMessage(), e);
String filename = defaultIfBlank(annotation.filename(), unknownFilename) + ".error.txt";
writeOne(pjp, annotation, null, new DownloadFileOutput(filename, ERROR_TEXT + e.getMessage()));
return null;
}
}
/**
* 写入空下载文件
*
* @param pjp 切点
* @param annotation 注解
* @param object 调用方法返回值对象
* @throws IOException 异常
*/
@SuppressWarnings({"unchecked"})
public void writeEmpty(ProceedingJoinPoint pjp, DownloadFile annotation, Object object) throws IOException {
String filename = defaultIfBlank(annotation.filename(), unknownFilename);
if (templateParser.isTemplate(filename)) {
Object context = templateParser.createContext(pjp, object, null);
filename = templateParser.parseTemplate(filename, context);
}
ResponseUtil.writeDownloadHeaders(response, filename, annotation.contentType(), isInline(annotation), annotation.headers());
response.setContentLengthLong(EMPTY_BYTE_ARRAY.length);
ServletOutputStream outputStream = response.getOutputStream();
outputStream.write(EMPTY_BYTE_ARRAY);
outputStream.flush();
response.flushBuffer();
}
/**
* 写入一个下载文件
*
* @param pjp 切点
* @param annotation 注解
* @param object 调用方法返回值对象
* @param fileOutput 文件对象
* @throws IOException 异常
*/
@SuppressWarnings({"unchecked"})
public void writeOne(ProceedingJoinPoint pjp, DownloadFile annotation, Object object, DownloadFileOutput fileOutput) throws IOException {
String filename;
if (fileOutput.isUseDefaultFilename()) {
filename = defaultIfBlank(annotation.filename(), () -> defaultIfBlank(fileOutput.getFilename(), unknownFilename));
} else {
filename = defaultIfBlank(fileOutput.getFilename(), () -> defaultIfBlank(annotation.filename(), unknownFilename));
}
if (templateParser.isTemplate(filename)) {
Object context = templateParser.createContext(pjp, object, null);
filename = templateParser.parseTemplate(filename, context);
}
ResponseUtil.writeDownloadHeaders(response, filename, annotation.contentType(), isInline(annotation), annotation.headers());
fileOutput.write(response.getOutputStream());
}
/**
* 写入压缩包流
*
* @param pjp 切点
* @param annotation 注解
* @param object 调用方法返回值对象
* @param fileOutputs 文件列表
* @throws IOException 异常
*/
@SuppressWarnings({"unchecked"})
public void writeZip(ProceedingJoinPoint pjp, DownloadFile annotation, Object object, List fileOutputs) throws IOException {
String filename = defaultIfBlank(annotation.filename(), () -> "压缩包." + annotation.compressFormat());
if (templateParser.isTemplate(filename)) {
Object context = templateParser.createContext(pjp, object, null);
filename = templateParser.parseTemplate(filename, context);
}
String extension = FilenameUtils.getExtension(filename);
if (extension.isBlank()) {
filename += "." + annotation.compressFormat();
}
downloadFileHandler.compressFiles(response, annotation, filename, fileOutputs);
}
/**
* 获取文件列表
*
* @param filename 文件名称
* @param object 文件对象
* @param isModelObject 是否是模型文件对象
* @return 文件列表
* @throws IOException 异常
*/
public List getFileOutputs(final String filename, final Object object, boolean isModelObject) throws IOException {
if (object == null) {
return Collections.emptyList();
}
if (object.getClass().isAnnotationPresent(DownloadFileModel.class)) {
try {
DownloadFileModelMetadata fileModelMetadata = getFileModelMetadata(object);
return getFileOutputs(defaultIfBlank(fileModelMetadata.getFilename(), filename), fileModelMetadata.getSource(), true);
} catch (Exception e) {
return Collections.singletonList(new DownloadFileOutput(filename + ".error.txt", ERROR_TEXT + object));
}
} else if (object instanceof DownloadFileModelMetadata fileModelMetadata) {
return getFileOutputs(defaultIfBlank(fileModelMetadata.getFilename(), filename), fileModelMetadata.getSource(), true);
}
DownloadFileOutput fileOutput = null;
if (object instanceof DownloadFileOutput fileOutput1) {
fileOutput = fileOutput1;
} else if (object instanceof String string) {
String zipEntryName = defaultIfBlank(filename, () -> downloadFileHandler.getFilename(string));
InputStream inputStream = downloadFileHandler.getFileInputStream(string);
if (inputStream != null) {
fileOutput = new DownloadFileOutput(zipEntryName, inputStream);
} else {
fileOutput = new DownloadFileOutput(zipEntryName + ".error.txt", ERROR_TEXT + string);
}
if (!isModelObject || filename == null) {
fileOutput.setUseDefaultFilename();
}
} else if (object instanceof File file) {
String zipEntryName = defaultIfBlank(filename, file::getName);
if (!file.exists() || !file.isFile()) {
fileOutput = new DownloadFileOutput(zipEntryName + ".error.txt", ERROR_TEXT + zipEntryName);
} else {
fileOutput = new DownloadFileOutput(zipEntryName, new FileInputStream(file));
}
if (!isModelObject || filename == null) {
fileOutput.setUseDefaultFilename();
}
} else if (object instanceof InputStream inputStream) {
fileOutput = new DownloadFileOutput(filename, inputStream);
} else if (object instanceof byte[] bytes) {
fileOutput = new DownloadFileOutput(filename, bytes);
} else if (object instanceof Resource resource) {
String zipEntryName = defaultIfBlank(filename, resource::getFilename);
fileOutput = new DownloadFileOutput(zipEntryName, resource.getInputStream());
if (!isModelObject || filename == null) {
fileOutput.setUseDefaultFilename();
}
} else if (object instanceof Collection> collection) {
List fileOutputs = new ArrayList<>();
for (Object o : collection) {
fileOutputs.addAll(getFileOutputs(filename, o, false));
}
return fileOutputs;
}
return fileOutput == null ? Collections.emptyList() : Collections.singletonList(fileOutput);
}
/**
* 使用默认值
*
* @param value 值
* @param defaultValueFunc 默认值
* @return 值
*/
public static String defaultIfBlank(String value, Supplier defaultValueFunc) {
if (value == null || value.isBlank()) {
return defaultValueFunc.get();
}
return value;
}
/**
* 使用默认值
*
* @param value 值
* @param defaultValue 默认值
* @return 值
*/
public static String defaultIfBlank(String value, String defaultValue) {
if (value == null || value.isBlank()) {
return defaultValue;
}
return value;
}
/**
* 获取一个不会重复的文件名称
*
* @param filenameSets 已存在的文件名称列表
* @param filename 文件名称
* @return 不会重复的文件名称
*/
public static String getFilename(Set filenameSets, String filename) {
String newFilename = filename;
int lastDot = newFilename.lastIndexOf('.');
String prefix = newFilename.substring(0, lastDot);
String extension = newFilename.substring(lastDot + 1);
int index = 1;
while (filenameSets.contains(newFilename)) {
newFilename = prefix + ".duplicate-" + index++ + "." + extension;
}
filenameSets.add(newFilename);
return newFilename;
}
/**
* 获取文件模型信息数据
*
* @param object 文件对象
* @return 文件模型
* @throws IllegalAccessException 异常
* @throws InvocationTargetException 异常
*/
public DownloadFileModelMetadata getFileModelMetadata(Object object) throws IllegalAccessException, InvocationTargetException {
String filename = null;
Object o = null;
Field[] declaredFields = object.getClass().getDeclaredFields();
for (Field declaredField : declaredFields) {
if (filename == null) {
DownloadFileName annotation1 = declaredField.getAnnotation(DownloadFileName.class);
if (annotation1 != null && declaredField.trySetAccessible()) {
filename = ObjectUtils.getDisplayString(declaredField.get(object));
}
}
if (o == null) {
DownloadFileObject annotation2 = declaredField.getAnnotation(DownloadFileObject.class);
if (annotation2 != null && declaredField.trySetAccessible()) {
o = declaredField.get(object);
}
}
if (filename != null && o != null) {
break;
}
}
if (filename == null || o == null) {
Method[] declaredMethods = object.getClass().getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
if (filename == null) {
DownloadFileName annotation1 = declaredMethod.getAnnotation(DownloadFileName.class);
if (annotation1 != null && declaredMethod.trySetAccessible()) {
filename = ObjectUtils.getDisplayString(declaredMethod.invoke(object));
}
}
if (o == null) {
DownloadFileObject annotation2 = declaredMethod.getAnnotation(DownloadFileObject.class);
if (annotation2 != null && declaredMethod.trySetAccessible()) {
o = declaredMethod.invoke(object);
}
}
if (filename != null && o != null) {
break;
}
}
}
return new DownloadFileModelMetadata(filename, o);
}
private boolean isInline(DownloadFile downloadFile) {
if (downloadFile.inlineParam().isBlank()) {
return downloadFile.inline();
}
String inlineParam = downloadFile.inlineParam();
if (request.getParameterMap().containsKey(inlineParam)) {
String parameter = request.getParameter(inlineParam);
return parameter == null || "true".equals(parameter) || parameter.isBlank();
} else {
return downloadFile.inline();
}
}
}