You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
110 lines
3.9 KiB
110 lines
3.9 KiB
package com.wok.supportbot.controller;
|
|
|
|
import com.wok.supportbot.service.LogViewerService;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.core.io.FileSystemResource;
|
|
import org.springframework.core.io.Resource;
|
|
import org.springframework.http.HttpHeaders;
|
|
import org.springframework.http.MediaType;
|
|
import org.springframework.http.ResponseEntity;
|
|
import org.springframework.security.access.prepost.PreAuthorize;
|
|
import org.springframework.web.bind.annotation.*;
|
|
|
|
import java.io.File;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
|
|
/**
|
|
* 系统日志查看接口
|
|
* <p>
|
|
* 提供日志文件列表、尾部内容查看、关键词搜索及文件下载功能。
|
|
* 仅 admin 角色可访问,所有文件操作限制在日志目录内,防止路径遍历攻击。
|
|
*/
|
|
@Slf4j
|
|
@RestController
|
|
@RequestMapping("/log")
|
|
@PreAuthorize("hasRole('admin')")
|
|
public class LogController {
|
|
|
|
@Autowired
|
|
private LogViewerService logViewerService;
|
|
|
|
/**
|
|
* 列出所有日志文件(名称、大小、修改时间等)
|
|
*/
|
|
@GetMapping("/files")
|
|
public ResponseEntity<Map<String, Object>> listFiles() {
|
|
try {
|
|
List<Map<String, Object>> files = logViewerService.listFiles();
|
|
return ResponseEntity.ok(Map.of(
|
|
"success", true,
|
|
"data", files
|
|
));
|
|
} catch (Exception e) {
|
|
log.error("获取日志文件列表失败", e);
|
|
return ResponseEntity.status(500).body(Map.of(
|
|
"success", false,
|
|
"message", "获取日志文件列表失败:" + e.getMessage()
|
|
));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 查看日志文件尾部内容
|
|
*
|
|
* @param fileName 日志文件名
|
|
* @param lines 读取最后 N 行(默认 200,上限 5000)
|
|
* @param keyword 可选搜索关键词
|
|
*/
|
|
@GetMapping("/view/{fileName}")
|
|
public ResponseEntity<Map<String, Object>> viewLog(
|
|
@PathVariable String fileName,
|
|
@RequestParam(defaultValue = "200") int lines,
|
|
@RequestParam(required = false) String keyword) {
|
|
try {
|
|
Map<String, Object> result = logViewerService.readLogTail(fileName, lines, keyword);
|
|
return ResponseEntity.ok(Map.of(
|
|
"success", true,
|
|
"data", result
|
|
));
|
|
} catch (IllegalArgumentException e) {
|
|
return ResponseEntity.badRequest().body(Map.of(
|
|
"success", false,
|
|
"message", e.getMessage()
|
|
));
|
|
} catch (Exception e) {
|
|
log.error("查看日志失败: {}", fileName, e);
|
|
return ResponseEntity.status(500).body(Map.of(
|
|
"success", false,
|
|
"message", "查看日志失败:" + e.getMessage()
|
|
));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 下载日志文件(原始文件流)
|
|
*
|
|
* @param fileName 日志文件名
|
|
*/
|
|
@GetMapping("/download/{fileName}")
|
|
public ResponseEntity<Resource> downloadLog(@PathVariable String fileName) {
|
|
try {
|
|
java.nio.file.Path filePath = logViewerService.resolveSafe(fileName);
|
|
File file = filePath.toFile();
|
|
FileSystemResource resource = new FileSystemResource(file);
|
|
|
|
return ResponseEntity.ok()
|
|
.header(HttpHeaders.CONTENT_DISPOSITION,
|
|
"attachment; filename=\"" + file.getName() + "\"")
|
|
.contentType(MediaType.TEXT_PLAIN)
|
|
.contentLength(file.length())
|
|
.body(resource);
|
|
} catch (IllegalArgumentException e) {
|
|
return ResponseEntity.badRequest().build();
|
|
} catch (Exception e) {
|
|
log.error("下载日志失败: {}", fileName, e);
|
|
return ResponseEntity.status(500).build();
|
|
}
|
|
}
|
|
}
|