『博客开发日记-后台』之日志导出接口的实现

本文最后更新于 2026年5月17日 下午

导出日志数据接口的实现


导出日志数据接口的需求

搜索需求和获取日志列表差不多

然后导出需求和导出评论的哪个差不多

要根据是否传入分页参数决定查询方式

代码实现

在 LogController 中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
@GetMapping("/export")
@SystemLog(businessName = "导出日志数据")
@ApiOperation(value = "导出日志数据接口", notes = "导出日志数据")
@ApiImplicitParams({
@ApiImplicitParam(name = "pageNum", value = "页号", dataType = "int", paramType = "query"),
@ApiImplicitParam(name = "pageSize", value = "每页数量", dataType = "int", paramType = "query")
})
public void exportLog(Integer pageNum, Integer pageSize, @Valid LogListDto logListDto, HttpServletResponse response)
{
try {
//调用服务层获取导出数据
ResponseResult result = visitLogService.exportLog(pageNum, pageSize, logListDto);

//检查结果
if (result.getCode() != 200 || result.getData() == null) {
throw new RuntimeException("获取导出数据失败");
}

//获取导出数据列表
@SuppressWarnings("unchecked")
List<VisitLogExportVo> exportData = (List<VisitLogExportVo>) result.getData();

//检查数据是否为空
if (exportData.isEmpty()) {
throw new RuntimeException("没有可导出的数据");
}

//生成文件名+时间(格式:日志数据_20260503_143056)
String fileName = "日志数据_" + new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());

//使用工具类导出Excel
ExcelExportUtil.exportExcel(response, exportData, VisitLogExportVo.class, fileName, "日志数据");

} catch (Exception e) {
//异常处理:只有在响应流未被写入时才能返回JSON错误
e.printStackTrace();

//检查响应是否已提交
if (!response.isCommitted()) {
try {
response.reset();
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");

ResponseResult result = ResponseResult.errorResult(
AppHttpCodeEnum.SYSTEM_ERROR.getCode(),
"导出失败: " + e.getMessage()
);
WebUtils.renderString(response, JSON.toJSONString(result));
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
}

创建 VisitLogExportVo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
/**
* 导出日志VO
* 用于EasyExcel导出日志数据
*
* @author mengze
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(description = "日志导出响应对象")
@ExcelIgnoreUnannotated // 只导出有@ExcelProperty注解的字段
public class VisitLogExportVo
{
@ColumnWidth(10)
@ExcelProperty(value = "日志ID", index = 0)
@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER)
@ApiModelProperty(value = "日志ID", example = "1")
private Long id;

@ColumnWidth(15)
@ExcelProperty(value = "操作人", index = 1)
@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER)
@ApiModelProperty(value = "操作人(游客/用户(显示用户名))", example = "云梦泽")
private String operator;

@ColumnWidth(25)
@ExcelProperty(value = "访问时间", index = 2)
@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER)
@ApiModelProperty(value = "访问时间", example = "2026-05-16 19:20:30")
private Date visitTime;

@ColumnWidth(15)
@ExcelProperty(value = "页面标题", index = 3)
@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER)
@ApiModelProperty(value = "页面标题", example = "文章")
private String pageTitle;

@ColumnWidth(15)
@ExcelProperty(value = "页面地址", index = 4)
@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER)
@ApiModelProperty(value = "访问的页面URL(页面地址)", example = "/post")
private String pageUrl;

@ColumnWidth(15)
@ExcelProperty(value = "页面前地址", index = 5)
@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER)
@ApiModelProperty(value = "来源页面(页面前地址)", example = "/log")
private String referrer;

@ColumnWidth(15)
@ExcelProperty(value = "请求方法", index = 6)
@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER)
@ApiModelProperty(value = "请求方法", example = "POST")
private String method;

@ColumnWidth(30)
@ExcelProperty(value = "IP地址", index = 7)
@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER)
@ApiModelProperty(value = "访问者IP地址(不明文入库)", example = "127.0.0.0")
private String ip;

@ColumnWidth(30)
@ExcelProperty(value = "地区信息", index = 8)
@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER)
@ApiModelProperty(value = "地区(国内外)", example = "中国|xx省|xx市|")
private String region;

@ColumnWidth(15)
@ExcelProperty(value = "浏览器类型", index = 9)
@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER)
@ApiModelProperty(value = "浏览器类型", example = "Edge")
private String browser;

@ColumnWidth(15)
@ExcelProperty(value = "操作系统", index = 10)
@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER)
@ApiModelProperty(value = "操作系统", example = "Windows")
private String os;

@ColumnWidth(15)
@ExcelProperty(value = "设备类型", index = 11)
@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER)
@ApiModelProperty(value = "设备类型", example = "PC")
private String deviceType;


@ColumnWidth(20)
@ExcelProperty(value = "页面执行时间", index = 12)
@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER)
@ApiModelProperty(value = "页面执行时间", example = "5")
private Integer executionTime;

}

在 VisitLogServiceImpl 中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
//导出日志
@Override
public ResponseResult exportLog(Integer pageNum, Integer pageSize, LogListDto logListDto)
{
//构建查询条件
LambdaQueryWrapper<VisitLog> queryWrapper = new LambdaQueryWrapper<>();

//根据关键字模糊查询操作人或页面标题
if (StringUtils.hasText(logListDto.getKeywords())) {
queryWrapper.and(wrapper -> wrapper
.like(VisitLog::getOperator, logListDto.getKeywords())
.or()
.like(VisitLog::getPageTitle, logListDto.getKeywords())
);
}

//按访问时间查询
if (logListDto.getVisitTime() != null && logListDto.getVisitTime().size() == 2)
{
//补全当天完整时间,因为前端只传 2026-04-01 不完整
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

Date startTime = sdf.parse(logListDto.getVisitTime().get(0) + " 00:00:00");
Date endTime = sdf.parse(logListDto.getVisitTime().get(1) + " 23:59:59");

queryWrapper.between(VisitLog::getVisitTime, startTime, endTime);
} catch (ParseException e) {
throw new RuntimeException("访问时间格式不正确", e);
}
}

//根据访问时间降序排序
queryWrapper.orderByDesc(VisitLog::getVisitTime);

//根据是否传入分页参数决定查询方式
List<VisitLog> logs;
if (pageNum != null && pageSize != null && pageNum > 0 && pageSize > 0) {
//分页查询
Page<VisitLog> page = new Page<>(pageNum, pageSize);
visitLogMapper.selectPage(page, queryWrapper);
logs = page.getRecords();
} else {
//查询所有符合条件的评论
logs = visitLogMapper.selectList(queryWrapper);
}

//转换为导出VO
List<VisitLogExportVo> exportData;
if (logs == null || logs.isEmpty()) {
exportData = new ArrayList<>();
} else {
exportData = BeanCopyUtils.copyBeanList(logs, VisitLogExportVo.class);
}

return ResponseResult.okResult(exportData);
}




PS:该系列只做为作者学习开发项目做的笔记用

不一定符合读者来学习,仅供参考


预告

后续会记录博客的开发过程

每次学习会做一份笔记来进行发表

“一花一世界,一叶一菩提”


版权所有 © 2026 云梦泽
欢迎访问我的个人网站:https://hgt12.github.io/


『博客开发日记-后台』之日志导出接口的实现
http://example.com/2026/05/17/『博客开发日记-后台』之日志导出接口的实现/
作者
云梦泽
发布于
2026年5月17日
更新于
2026年5月17日
许可协议