Compare commits
No commits in common. '631872ec47c0ff1c5ca76c4e5772878689ac904f' and 'd25c6e6a581e319380af271735c52418709e44be' have entirely different histories.
631872ec47
...
d25c6e6a58
@ -1,189 +0,0 @@ |
|||||||
package com.alops.web.controller.LlmKnowledgeController; |
|
||||||
|
|
||||||
import java.io.File; |
|
||||||
import java.io.IOException; |
|
||||||
import javax.servlet.http.HttpServletRequest; |
|
||||||
import javax.servlet.http.HttpServletResponse; |
|
||||||
|
|
||||||
import com.alops.chat.entity.UploadedFile; |
|
||||||
import com.alops.chat.service.UploadedFileService; |
|
||||||
import com.alops.common.config.RuoYiConfig; |
|
||||||
import com.alops.common.core.controller.BaseController; |
|
||||||
import com.alops.common.utils.file.FileUtils; |
|
||||||
import com.alops.common.utils.file.FileTypeUtils; |
|
||||||
import com.alops.common.utils.StringUtils; |
|
||||||
import org.slf4j.Logger; |
|
||||||
import org.slf4j.LoggerFactory; |
|
||||||
import org.springframework.beans.factory.annotation.Autowired; |
|
||||||
import org.springframework.http.MediaType; |
|
||||||
import org.springframework.security.access.prepost.PreAuthorize; |
|
||||||
import org.springframework.web.bind.annotation.GetMapping; |
|
||||||
import org.springframework.web.bind.annotation.PathVariable; |
|
||||||
import org.springframework.web.bind.annotation.RequestMapping; |
|
||||||
import org.springframework.web.bind.annotation.RestController; |
|
||||||
|
|
||||||
import java.net.URLEncoder; |
|
||||||
import java.nio.charset.StandardCharsets; |
|
||||||
|
|
||||||
/** |
|
||||||
* 文件下载和预览控制器 |
|
||||||
* |
|
||||||
* @author lingma |
|
||||||
*/ |
|
||||||
@RestController |
|
||||||
@RequestMapping("/QandA/knowledge/file") |
|
||||||
public class FileController extends BaseController { |
|
||||||
private static final Logger log = LoggerFactory.getLogger(FileController.class); |
|
||||||
|
|
||||||
@Autowired |
|
||||||
private UploadedFileService uploadedFileService; |
|
||||||
|
|
||||||
/** |
|
||||||
* 下载文件 |
|
||||||
* |
|
||||||
* @param fileId 文件ID |
|
||||||
* @param response 响应对象 |
|
||||||
*/ |
|
||||||
@PreAuthorize("@ss.hasPermi('QandA:knowledge:filedownload')") |
|
||||||
@GetMapping("/download/{fileId}") |
|
||||||
public void download(@PathVariable Long fileId, HttpServletResponse response, HttpServletRequest request) { |
|
||||||
try { |
|
||||||
UploadedFile uploadedFile = uploadedFileService.findById(fileId); |
|
||||||
if (uploadedFile == null) { |
|
||||||
response.sendError(HttpServletResponse.SC_NOT_FOUND, "文件未找到"); |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
// 获取文件路径
|
|
||||||
String filePath = uploadedFile.getFilePath(); |
|
||||||
// 获取实际文件路径(处理配置文件前缀)
|
|
||||||
String realPath = RuoYiConfig.getProfile() + filePath.replaceFirst("/profile", ""); |
|
||||||
|
|
||||||
// 检查文件是否存在
|
|
||||||
File file = new File(realPath); |
|
||||||
if (!file.exists()) { |
|
||||||
response.sendError(HttpServletResponse.SC_NOT_FOUND, "文件未找到"); |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
// 检查文件是否允许下载
|
|
||||||
if (!FileUtils.checkAllowDownload(realPath)) { |
|
||||||
throw new Exception(StringUtils.format("文件({})非法,不允许下载。", realPath)); |
|
||||||
} |
|
||||||
|
|
||||||
// 设置下载文件名(从文件路径中提取真实文件名)
|
|
||||||
String fileName = FileUtils.getName(realPath); |
|
||||||
if (StringUtils.isEmpty(fileName)) { |
|
||||||
fileName = uploadedFile.getSource(); |
|
||||||
// 如果source中也不包含扩展名,则尝试添加扩展名
|
|
||||||
String extension = uploadedFile.getFormat(); |
|
||||||
if (StringUtils.isNotEmpty(extension) && !fileName.endsWith("." + extension)) { |
|
||||||
fileName = fileName + "." + extension; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// 对文件名进行编码以支持中文
|
|
||||||
String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.toString()) |
|
||||||
.replaceAll("\\+", "%20"); |
|
||||||
|
|
||||||
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); |
|
||||||
response.setHeader("Content-Disposition", "attachment; filename=" + encodedFileName); |
|
||||||
FileUtils.writeBytes(realPath, response.getOutputStream()); |
|
||||||
} catch (Exception e) { |
|
||||||
log.error("下载文件失败", e); |
|
||||||
try { |
|
||||||
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "下载文件失败: " + e.getMessage()); |
|
||||||
} catch (IOException ioException) { |
|
||||||
log.error("设置错误响应失败", ioException); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 预览文件 |
|
||||||
* |
|
||||||
* @param fileId 文件ID |
|
||||||
* @param response 响应对象 |
|
||||||
*/ |
|
||||||
@PreAuthorize("@ss.hasPermi('QandA:knowledge:filepreview')") |
|
||||||
@GetMapping("/preview/{fileId}") |
|
||||||
public void preview(@PathVariable Long fileId, HttpServletResponse response, HttpServletRequest request) { |
|
||||||
try { |
|
||||||
UploadedFile uploadedFile = uploadedFileService.findById(fileId); |
|
||||||
if (uploadedFile == null) { |
|
||||||
response.sendError(HttpServletResponse.SC_NOT_FOUND, "文件未找到"); |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
// 获取文件路径
|
|
||||||
String filePath = uploadedFile.getFilePath(); |
|
||||||
// 获取实际文件路径(处理配置文件前缀)
|
|
||||||
String realPath = RuoYiConfig.getProfile() + filePath.replaceFirst("/profile", ""); |
|
||||||
|
|
||||||
// 检查文件是否存在
|
|
||||||
File file = new File(realPath); |
|
||||||
if (!file.exists()) { |
|
||||||
response.sendError(HttpServletResponse.SC_NOT_FOUND, "文件未找到"); |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
// 检查文件是否允许预览
|
|
||||||
if (!FileUtils.checkAllowDownload(realPath)) { |
|
||||||
throw new Exception(StringUtils.format("文件({})非法,不允许预览。", realPath)); |
|
||||||
} |
|
||||||
|
|
||||||
// 设置Content-Type以便浏览器预览
|
|
||||||
String fileExtension = FileTypeUtils.getFileType(uploadedFile.getSource()); |
|
||||||
if (StringUtils.isEmpty(fileExtension)) { |
|
||||||
fileExtension = uploadedFile.getFormat(); |
|
||||||
} |
|
||||||
String contentType = getContentTypeByExtension(fileExtension); |
|
||||||
if (contentType != null) { |
|
||||||
response.setContentType(contentType); |
|
||||||
} else { |
|
||||||
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); |
|
||||||
} |
|
||||||
|
|
||||||
FileUtils.writeBytes(realPath, response.getOutputStream()); |
|
||||||
} catch (Exception e) { |
|
||||||
log.error("预览文件失败", e); |
|
||||||
try { |
|
||||||
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "预览文件失败: " + e.getMessage()); |
|
||||||
} catch (IOException ioException) { |
|
||||||
log.error("设置错误响应失败", ioException); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 根据文件扩展名获取对应的Content-Type |
|
||||||
* |
|
||||||
* @param extension 文件扩展名 |
|
||||||
* @return Content-Type字符串 |
|
||||||
*/ |
|
||||||
private String getContentTypeByExtension(String extension) { |
|
||||||
if (StringUtils.isEmpty(extension)) { |
|
||||||
return MediaType.APPLICATION_OCTET_STREAM_VALUE; |
|
||||||
} |
|
||||||
|
|
||||||
switch (extension.toLowerCase()) { |
|
||||||
case "txt": |
|
||||||
return "text/plain;charset=UTF-8"; |
|
||||||
case "doc": |
|
||||||
return "application/msword"; |
|
||||||
case "docx": |
|
||||||
return "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; |
|
||||||
case "pdf": |
|
||||||
return "application/pdf"; |
|
||||||
case "jpg": |
|
||||||
case "jpeg": |
|
||||||
return "image/jpeg"; |
|
||||||
case "png": |
|
||||||
return "image/png"; |
|
||||||
case "gif": |
|
||||||
return "image/gif"; |
|
||||||
default: |
|
||||||
return MediaType.APPLICATION_OCTET_STREAM_VALUE; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
Loading…
Reference in new issue