添加操作日志
This commit is contained in:
5
pom.xml
5
pom.xml
@@ -158,6 +158,11 @@
|
||||
<artifactId>xtools-app-sys-scheduled</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.xujun</groupId>
|
||||
<artifactId>xtools-app-sys-tag</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<!-- Sys 模块 end -->
|
||||
|
||||
<!-- Gen 模块 begin -->
|
||||
|
||||
@@ -90,6 +90,10 @@
|
||||
<groupId>org.xujun</groupId>
|
||||
<artifactId>xtools-app-sys-auth</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.xujun</groupId>
|
||||
<artifactId>xtools-app-sys-tag</artifactId>
|
||||
</dependency>
|
||||
<!-- 项目模块 end -->
|
||||
|
||||
<!-- mapstruct begin -->
|
||||
|
||||
@@ -367,10 +367,10 @@ import {useSettingsStore} from "@/store";
|
||||
import {DictItem, PageReq, PageResult} from "@/types/global";
|
||||
import SysCommonAPI from "@/api/sys/sys-common-api";
|
||||
#else
|
||||
import {PageReq} from "@/types/global";
|
||||
import {PageReq, PageResult} from "@/types/global";
|
||||
#end
|
||||
#if($exportExcel)
|
||||
import {FileUtils, Format} from "@/utils/utils";
|
||||
import {FileUtils, Format} from "@/utils";
|
||||
#end
|
||||
import ${table.entityName}API, {
|
||||
EditForm as ${table.entityName}EditForm,
|
||||
|
||||
@@ -8,3 +8,9 @@ sys:
|
||||
log:
|
||||
# 存储类型(elasticsearch|mysql)
|
||||
type: ${SYS_LOG_TYPE:elasticsearch}
|
||||
# 最大保存天数
|
||||
max-days: 2
|
||||
# 忽略操作日志
|
||||
ignore-opt-log:
|
||||
- /sys/dict-item/get-by-code/*
|
||||
- /**/page
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
<module>xtools-app-sys-scheduled</module>
|
||||
<module>xtools-app-sys-risk</module>
|
||||
<module>xtools-app-sys-file-web</module>
|
||||
<module>xtools-app-sys-tag</module>
|
||||
</modules>
|
||||
|
||||
</project>
|
||||
@@ -11,6 +11,7 @@ import org.springframework.core.Ordered;
|
||||
import org.springframework.stereotype.Component;
|
||||
import xtools.app.common.cache.enums.AppCache;
|
||||
import xtools.app.sys.auth.model.dto.LoginUserDto;
|
||||
import xtools.app.sys.auth.model.dto.OptLogDto;
|
||||
import xtools.app.sys.auth.utils.AuthUtils;
|
||||
import xtools.app.sys.auth.utils.PremUtils;
|
||||
import xtools.app.sys.auth.whitelist.AuthWhitelist;
|
||||
@@ -22,14 +23,18 @@ import xtools.boot.cache.redis.base.RedisService;
|
||||
import xtools.boot.core.holder.CommonHolder;
|
||||
import xtools.boot.core.utils.PathPatternUtils;
|
||||
import xtools.boot.core.utils.SpringContextUtils;
|
||||
import xtools.boot.log.LogBus;
|
||||
import xtools.boot.log.enums.LogBusBaseType;
|
||||
import xtools.boot.mask.utils.MaskIgnoreUtils;
|
||||
import xtools.boot.web.filter.base.BaseFilter;
|
||||
import xtools.core.CollectionUtils;
|
||||
import xtools.core.StringUtils;
|
||||
import xtools.core.enums.LogLevel;
|
||||
import xtools.web.HeaderUtils;
|
||||
import xtools.web.HttpServletUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
@@ -47,7 +52,7 @@ import java.util.Set;
|
||||
* @date : 2026/1/31 21:18
|
||||
*/
|
||||
@Component
|
||||
public class AuthFilter extends BaseFilter implements Ordered, BaseParams {
|
||||
public class AuthFilter extends BaseFilter implements Ordered, BootCommonConstant, BaseParams {
|
||||
|
||||
/**
|
||||
* 微服务标识
|
||||
@@ -157,6 +162,10 @@ public class AuthFilter extends BaseFilter implements Ordered, BaseParams {
|
||||
) throws ServletException, IOException {
|
||||
// 获取访问 uri
|
||||
String uri = HeaderUtils.getUri(request);
|
||||
String ip = HeaderUtils.getIp(request);
|
||||
OptLogDto log = new OptLogDto();
|
||||
log.setUri(uri);
|
||||
log.setIp(ip);
|
||||
|
||||
// 忽略权限校验
|
||||
if (checkAuthWhiteList(uri)) {
|
||||
@@ -184,11 +193,13 @@ public class AuthFilter extends BaseFilter implements Ordered, BaseParams {
|
||||
HttpServletUtils.respWriter(response, JSONObject.from(new Result<>(ResultType.UNAUTHORIZED, null)));
|
||||
return;
|
||||
}
|
||||
|
||||
log.setAccountId(loginUser.getId());
|
||||
log.setAccount(loginUser.getAccount());
|
||||
|
||||
// 校验 uri 访问权限
|
||||
String method = request.getMethod();
|
||||
if (!PremUtils.checkInterfacePerm(uri, method, loginUser.getRoleIds())) {
|
||||
saveOptLog(log, "URI访问权限校验失败");
|
||||
HttpServletUtils.respWriter(response, JSONObject.from(new Result<>(ResultType.FORBIDDEN, null)));
|
||||
return;
|
||||
}
|
||||
@@ -199,7 +210,27 @@ public class AuthFilter extends BaseFilter implements Ordered, BaseParams {
|
||||
|
||||
// 校验忽略掩码
|
||||
checkIgnoreMask();
|
||||
CommonHolder.set(GET_SWAGGER_TAG, true);
|
||||
filterChain.doFilter(request, response);
|
||||
saveOptLog(log, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存操作日志
|
||||
*
|
||||
* @param log 日志
|
||||
* @param memo 备注
|
||||
*/
|
||||
private void saveOptLog(OptLogDto log, String memo) {
|
||||
Object tag = CommonHolder.get(SWAGGER_TAG);
|
||||
if (Objects.nonNull(tag)) {
|
||||
{
|
||||
log.setTitle(tag.toString());
|
||||
}
|
||||
}
|
||||
log.setMemo(memo);
|
||||
log.setGmtCreate(Instant.now());
|
||||
LogBus.init(LogLevel.INFO, LogBusBaseType.OPT_LOG).data(log).save();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
package xtools.app.sys.auth.model.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
|
||||
|
||||
/**
|
||||
* <p>Title : OptLogDto</p>
|
||||
* <p>Description : OptLogDto</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 1.0.0
|
||||
* @date : 2026/6/2 17:28
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class OptLogDto implements Serializable {
|
||||
|
||||
/**
|
||||
* 日志追踪id
|
||||
*/
|
||||
@Schema(description = "日志追踪id")
|
||||
private String traceId;
|
||||
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
@Schema(description = "标题")
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 账号ID
|
||||
*/
|
||||
@Schema(description = "账号ID")
|
||||
private Long accountId;
|
||||
|
||||
/**
|
||||
* 账号
|
||||
*/
|
||||
@Schema(description = "账号")
|
||||
private String account;
|
||||
|
||||
/**
|
||||
* IP
|
||||
*/
|
||||
@Schema(description = "IP")
|
||||
private String ip;
|
||||
|
||||
/**
|
||||
* 操作URI
|
||||
*/
|
||||
@Schema(description = "操作URI")
|
||||
private String uri;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@Schema(description = "备注")
|
||||
private String memo;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@Schema(description = "创建时间", example = "2026-01-05 10:32:00")
|
||||
private Instant gmtCreate;
|
||||
|
||||
}
|
||||
@@ -157,6 +157,10 @@
|
||||
<groupId>org.xujun</groupId>
|
||||
<artifactId>xtools-app-sys-risk</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.xujun</groupId>
|
||||
<artifactId>xtools-app-sys-tag</artifactId>
|
||||
</dependency>
|
||||
<!-- 项目模块 end -->
|
||||
|
||||
<!-- mapstruct begin -->
|
||||
|
||||
@@ -4,6 +4,9 @@ import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>Title : SysConfig</p>
|
||||
* <p>Description : SysConfig</p>
|
||||
@@ -57,6 +60,11 @@ public class SysConfig {
|
||||
* 最大保存天数
|
||||
*/
|
||||
private int maxDays = 2;
|
||||
|
||||
/**
|
||||
* 忽略操作日志
|
||||
*/
|
||||
private List<String> ignoreOptLog = new ArrayList<>();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
package xtools.app.sys.controller;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import xtools.app.sys.model.dto.excel.SysOptLogExcel;
|
||||
import xtools.app.sys.model.dto.req.SysOptLogPageReq;
|
||||
import xtools.app.sys.model.dto.resp.SysOptLogResp;
|
||||
import xtools.app.sys.service.SysOptLogService;
|
||||
import xtools.boot.api.exection.BizError;
|
||||
import xtools.boot.api.model.dto.Result;
|
||||
import xtools.boot.api.model.dto.page.PageReq;
|
||||
import xtools.boot.api.model.dto.page.PageResp;
|
||||
import xtools.extend.office.FesodUtils;
|
||||
import xtools.web.HttpServletUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>Title : SysOptLogController</p>
|
||||
* <p>Description : 系统操作日志 Controller</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : xujun
|
||||
* @version : 1.0.0
|
||||
* @date : 2026-06-02 16:44:47
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Tag(name = "系统操作日志")
|
||||
@RestController
|
||||
@RequestMapping("/sys/opt-log")
|
||||
public class SysOptLogController {
|
||||
|
||||
private final SysOptLogService sysOptLogService;
|
||||
|
||||
@Operation(summary = "分页请求")
|
||||
@PostMapping("page")
|
||||
public Result<PageResp<SysOptLogResp>> page(@RequestBody @Valid PageReq<SysOptLogPageReq> pageReq) {
|
||||
return sysOptLogService.page(pageReq);
|
||||
}
|
||||
|
||||
@Operation(summary = "导出Excel")
|
||||
@PostMapping("export")
|
||||
public void exportExcel(@RequestBody @Valid SysOptLogPageReq req, HttpServletResponse response) {
|
||||
String sheetName = "系统操作日志";
|
||||
String filename = sheetName + ".xlsx";
|
||||
List<SysOptLogExcel> dataList = sysOptLogService.exportExcel(req);
|
||||
try {
|
||||
FesodUtils.write(response.getOutputStream(), SysOptLogExcel.class, sheetName, dataList);
|
||||
} catch (IOException e) {
|
||||
throw new BizError("导出Excel失败");
|
||||
}
|
||||
// 设置 header 和 contentType.写在最后的原因是,避免报错时,响应 contentType 已经被修改
|
||||
HttpServletUtils.addDownloadHeader(response, filename);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package xtools.app.sys.convert;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import xtools.app.sys.auth.model.dto.OptLogDto;
|
||||
import xtools.app.sys.model.dto.excel.SysOptLogExcel;
|
||||
import xtools.app.sys.model.dto.resp.SysOptLogResp;
|
||||
import xtools.app.sys.model.entity.SysOptLog;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>Title : SysOptLogConvert</p>
|
||||
* <p>Description : 系统操作日志 Convert</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : xujun
|
||||
* @version : 1.0.0
|
||||
* @date : 2026-06-02 16:44:47
|
||||
*/
|
||||
@Mapper(componentModel = "spring")
|
||||
public interface SysOptLogConvert {
|
||||
|
||||
/**
|
||||
* 实体转响应
|
||||
*
|
||||
* @param data 实体
|
||||
* @return 响应
|
||||
*/
|
||||
SysOptLogResp entityToResp(SysOptLog data);
|
||||
|
||||
/**
|
||||
* 批量实体转响应
|
||||
*
|
||||
* @param dataList 批量实体
|
||||
* @return 响应
|
||||
*/
|
||||
List<SysOptLogResp> entityToRespList(List<SysOptLog> dataList);
|
||||
|
||||
/**
|
||||
* 实体转Excel
|
||||
*
|
||||
* @param data 实体
|
||||
* @return Excel
|
||||
*/
|
||||
SysOptLogExcel entityToExcel(SysOptLog data);
|
||||
|
||||
|
||||
/**
|
||||
* DTO转实体
|
||||
*
|
||||
* @param data DTO
|
||||
* @return 实体
|
||||
*/
|
||||
SysOptLog dtoToEntity(OptLogDto data);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package xtools.app.sys.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import xtools.app.sys.model.entity.SysOptLog;
|
||||
|
||||
/**
|
||||
* <p>Title : SysOptLogMapper</p>
|
||||
* <p>Description : 系统操作日志 Mapper 接口</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : xujun
|
||||
* @version : 1.0.0
|
||||
* @date : 2026-06-02 16:44:47
|
||||
*/
|
||||
@Mapper
|
||||
public interface SysOptLogMapper extends BaseMapper<SysOptLog> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package xtools.app.sys.model.dto.excel;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.fesod.sheet.annotation.ExcelProperty;
|
||||
import org.apache.fesod.sheet.annotation.format.DateTimeFormat;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* <p>Title : SysOptLogExcel</p>
|
||||
* <p>Description : 系统操作日志Excel对象</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : xujun
|
||||
* @version : 1.0.0
|
||||
* @date : 2026-06-02 16:44:47
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SysOptLogExcel implements Serializable {
|
||||
|
||||
/**
|
||||
* 日志追踪id
|
||||
*/
|
||||
@ExcelProperty("日志追踪id")
|
||||
private String traceId;
|
||||
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
@ExcelProperty("标题")
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 账号ID
|
||||
*/
|
||||
@ExcelProperty("账号ID")
|
||||
private Long accountId;
|
||||
|
||||
/**
|
||||
* 账号
|
||||
*/
|
||||
@ExcelProperty("账号")
|
||||
private String account;
|
||||
|
||||
/**
|
||||
* IP
|
||||
*/
|
||||
@ExcelProperty("IP")
|
||||
private String ip;
|
||||
|
||||
/**
|
||||
* 地址
|
||||
*/
|
||||
@ExcelProperty("地址")
|
||||
private String addr;
|
||||
|
||||
/**
|
||||
* 操作URI
|
||||
*/
|
||||
@ExcelProperty("操作URI")
|
||||
private String uri;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@ExcelProperty("备注")
|
||||
private String memo;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@ExcelProperty("创建时间")
|
||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
||||
private Date gmtCreate;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package xtools.app.sys.model.dto.req;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
|
||||
/**
|
||||
* <p>Title : SysOptLogPageReq</p>
|
||||
* <p>Description : 系统操作日志分页请求对象</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : xujun
|
||||
* @version : 1.0.0
|
||||
* @date : 2026-06-02 16:44:47
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SysOptLogPageReq implements Serializable {
|
||||
|
||||
/**
|
||||
* ID
|
||||
*/
|
||||
@Schema(description = "ID")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 日志追踪id
|
||||
*/
|
||||
@Schema(description = "日志追踪id")
|
||||
private String traceId;
|
||||
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
@Schema(description = "标题")
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 账号ID
|
||||
*/
|
||||
@Schema(description = "账号ID")
|
||||
private Long accountId;
|
||||
|
||||
/**
|
||||
* 账号
|
||||
*/
|
||||
@Schema(description = "账号")
|
||||
private String account;
|
||||
|
||||
/**
|
||||
* IP
|
||||
*/
|
||||
@Schema(description = "IP")
|
||||
private String ip;
|
||||
|
||||
/**
|
||||
* 地址
|
||||
*/
|
||||
@Schema(description = "地址")
|
||||
private String addr;
|
||||
|
||||
/**
|
||||
* 地址code
|
||||
*/
|
||||
@Schema(description = "地址code")
|
||||
private String addrCode;
|
||||
|
||||
/**
|
||||
* 操作URI
|
||||
*/
|
||||
@Schema(description = "操作URI")
|
||||
private String uri;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@Schema(description = "备注")
|
||||
private String memo;
|
||||
|
||||
/**
|
||||
* 创建时间(范围)
|
||||
*/
|
||||
@Schema(description = "创建时间(范围)", example = "['2026-01-01 00:00:00', '2026-01-01 12:00:00']")
|
||||
private Instant[] gmtCreateRange;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package xtools.app.sys.model.dto.resp;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import xtools.boot.api.model.entity.BaseEntity;
|
||||
|
||||
/**
|
||||
* <p>Title : SysOptLogResp</p>
|
||||
* <p>Description : 系统操作日志响应对象</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : xujun
|
||||
* @version : 1.0.0
|
||||
* @date : 2026-06-02 16:44:47
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class SysOptLogResp extends BaseEntity {
|
||||
|
||||
/**
|
||||
* ID
|
||||
*/
|
||||
@Schema(description = "ID")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 日志追踪id
|
||||
*/
|
||||
@Schema(description = "日志追踪id")
|
||||
private String traceId;
|
||||
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
@Schema(description = "标题")
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 账号ID
|
||||
*/
|
||||
@Schema(description = "账号ID")
|
||||
private Long accountId;
|
||||
|
||||
/**
|
||||
* 账号
|
||||
*/
|
||||
@Schema(description = "账号")
|
||||
private String account;
|
||||
|
||||
/**
|
||||
* IP
|
||||
*/
|
||||
@Schema(description = "IP")
|
||||
private String ip;
|
||||
|
||||
/**
|
||||
* 地址
|
||||
*/
|
||||
@Schema(description = "地址")
|
||||
private String addr;
|
||||
|
||||
/**
|
||||
* 地址code
|
||||
*/
|
||||
@Schema(description = "地址code")
|
||||
private String addrCode;
|
||||
|
||||
/**
|
||||
* 操作URI
|
||||
*/
|
||||
@Schema(description = "操作URI")
|
||||
private String uri;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@Schema(description = "备注")
|
||||
private String memo;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package xtools.app.sys.model.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
|
||||
/**
|
||||
* <p>Title : SysOptLog</p>
|
||||
* <p>Description : 系统操作日志实体对象</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : xujun
|
||||
* @version : 1.0.0
|
||||
* @date : 2026-06-02 16:44:47
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@TableName("sys_opt_log")
|
||||
public class SysOptLog implements Serializable {
|
||||
|
||||
/**
|
||||
* ID
|
||||
*/
|
||||
@Schema(description = "ID")
|
||||
@TableId(value = "id", type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 日志追踪id
|
||||
*/
|
||||
@Schema(description = "日志追踪id")
|
||||
@TableField(value = "trace_id")
|
||||
private String traceId;
|
||||
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
@Schema(description = "标题")
|
||||
@TableField(value = "title")
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 账号ID
|
||||
*/
|
||||
@Schema(description = "账号ID")
|
||||
@TableField(value = "account_id")
|
||||
private Long accountId;
|
||||
|
||||
/**
|
||||
* 账号
|
||||
*/
|
||||
@Schema(description = "账号")
|
||||
@TableField(value = "account")
|
||||
private String account;
|
||||
|
||||
/**
|
||||
* IP
|
||||
*/
|
||||
@Schema(description = "IP")
|
||||
@TableField(value = "ip")
|
||||
private String ip;
|
||||
|
||||
/**
|
||||
* 地址
|
||||
*/
|
||||
@Schema(description = "地址")
|
||||
@TableField(value = "addr")
|
||||
private String addr;
|
||||
|
||||
/**
|
||||
* 地址code
|
||||
*/
|
||||
@Schema(description = "地址code")
|
||||
@TableField(value = "addr_code")
|
||||
private String addrCode;
|
||||
|
||||
/**
|
||||
* 操作URI
|
||||
*/
|
||||
@Schema(description = "操作URI")
|
||||
@TableField(value = "uri")
|
||||
private String uri;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@Schema(description = "备注")
|
||||
@TableField(value = "memo")
|
||||
private String memo;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField(value = "gmt_create")
|
||||
@Schema(description = "创建时间", example = "2026-01-05 10:32:00")
|
||||
private Instant gmtCreate;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package xtools.app.sys.service;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import xtools.app.sys.model.dto.excel.SysOptLogExcel;
|
||||
import xtools.app.sys.model.dto.req.SysOptLogPageReq;
|
||||
import xtools.app.sys.model.dto.resp.SysOptLogResp;
|
||||
import xtools.boot.api.model.dto.Result;
|
||||
import xtools.boot.api.model.dto.page.PageReq;
|
||||
import xtools.boot.api.model.dto.page.PageResp;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>Title : SysOptLogService</p>
|
||||
* <p>Description : 系统操作日志 Service</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : xujun
|
||||
* @version : 1.0.0
|
||||
* @date : 2026-06-02 16:44:47
|
||||
*/
|
||||
public interface SysOptLogService {
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
*
|
||||
* @param pageReq 分页请求
|
||||
* @return 分页结果
|
||||
*/
|
||||
Result<PageResp<SysOptLogResp>> page(PageReq<SysOptLogPageReq> pageReq);
|
||||
|
||||
/**
|
||||
* 保存日志
|
||||
*
|
||||
* @param traceId 日志追踪 ID
|
||||
* @param logData 日志
|
||||
*/
|
||||
void save(String traceId, JSONObject logData);
|
||||
|
||||
/**
|
||||
* 导出 Excel
|
||||
*
|
||||
* @param req 请求参数
|
||||
* @return Excel 数据
|
||||
*/
|
||||
List<SysOptLogExcel> exportExcel(SysOptLogPageReq req);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package xtools.app.sys.service.base;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import xtools.app.sys.mapper.SysOptLogMapper;
|
||||
import xtools.app.sys.model.entity.SysOptLog;
|
||||
|
||||
/**
|
||||
* <p>Title : SysOptLogBaseService</p>
|
||||
* <p>Description : 系统操作日志 BaseService</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : xujun
|
||||
* @version : 1.0.0
|
||||
* @date : 2026-06-02 16:44:47
|
||||
*/
|
||||
@Component
|
||||
public class SysOptLogBaseService extends ServiceImpl<SysOptLogMapper, SysOptLog> {
|
||||
}
|
||||
@@ -9,7 +9,9 @@ import org.springframework.stereotype.Service;
|
||||
import xtools.app.common.log.bus.service.LogBusService;
|
||||
import xtools.app.sys.model.entity.SysLog;
|
||||
import xtools.app.sys.service.SysLogService;
|
||||
import xtools.app.sys.service.SysOptLogService;
|
||||
import xtools.boot.api.model.dto.log.LogTrack;
|
||||
import xtools.boot.log.enums.LogBusBaseType;
|
||||
import xtools.boot.log.model.dto.LogBody;
|
||||
import xtools.boot.log.model.dto.RunInfo;
|
||||
import xtools.core.CollectionUtils;
|
||||
@@ -37,6 +39,8 @@ public class LogBusServiceImpl implements LogBusService {
|
||||
|
||||
private final SysLogService sysLogService;
|
||||
|
||||
private final SysOptLogService sysOptLogService;
|
||||
|
||||
/**
|
||||
* 保存日志
|
||||
*
|
||||
@@ -44,18 +48,25 @@ public class LogBusServiceImpl implements LogBusService {
|
||||
*/
|
||||
@Override
|
||||
public void saveLog(LogBody logBody) {
|
||||
LogTrack logTrack = logBody.getLogTrack();
|
||||
RunInfo runInfo = logBody.getRunInfo();
|
||||
// 获取日志类型
|
||||
String logType = logBody.getType();
|
||||
|
||||
LogTrack logTrack = logBody.getLogTrack();
|
||||
JSONObject logData = logBody.getLogData();
|
||||
if (CollectionUtils.isEmpty(logData)) {
|
||||
logData = new JSONObject();
|
||||
}
|
||||
|
||||
// 扩展日志处理
|
||||
if (extLog(logType, logTrack.traceId(), logData)) {
|
||||
return;
|
||||
}
|
||||
|
||||
RunInfo runInfo = logBody.getRunInfo();
|
||||
JSONArray stackTrace = logBody.getStackTrace();
|
||||
|
||||
// 处理数据
|
||||
String title = logBody.getTitle();
|
||||
String logType = logBody.getType();
|
||||
title = StringUtils.isBlank(title) ? logType : title;
|
||||
// 获取请求ip
|
||||
String ip = logData.getString("ip");
|
||||
@@ -90,4 +101,20 @@ public class LogBusServiceImpl implements LogBusService {
|
||||
log.error("保存日志异常,logBody:{}", JsonUtils.toStrPretty(logBody), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 扩展日志
|
||||
*
|
||||
* @param logType 日志类型
|
||||
* @param traceId 日志追踪 ID
|
||||
* @param logData 日志数据
|
||||
* @return 保存结果
|
||||
*/
|
||||
private boolean extLog(String logType, String traceId, JSONObject logData) {
|
||||
if (LogBusBaseType.OPT_LOG.desc().equals(logType)) {
|
||||
sysOptLogService.save(traceId, logData);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,187 @@
|
||||
package xtools.app.sys.service.impl;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.stereotype.Service;
|
||||
import xtools.app.sys.auth.model.dto.OptLogDto;
|
||||
import xtools.app.sys.config.SysConfig;
|
||||
import xtools.app.sys.convert.SysOptLogConvert;
|
||||
import xtools.app.sys.model.dto.excel.SysOptLogExcel;
|
||||
import xtools.app.sys.model.dto.req.SysOptLogPageReq;
|
||||
import xtools.app.sys.model.dto.resp.SysOptLogResp;
|
||||
import xtools.app.sys.model.entity.SysOptLog;
|
||||
import xtools.app.sys.service.SysOptLogService;
|
||||
import xtools.app.sys.service.base.SysOptLogBaseService;
|
||||
import xtools.boot.api.model.dto.Result;
|
||||
import xtools.boot.api.model.dto.page.PageReq;
|
||||
import xtools.boot.api.model.dto.page.PageResp;
|
||||
import xtools.boot.core.utils.PathPatternUtils;
|
||||
import xtools.boot.db.mybatisplus.utils.QueryUtils;
|
||||
import xtools.boot.ip.utils.IpUtils;
|
||||
import xtools.core.StringUtils;
|
||||
import xtools.extend.dto.IpAddrDto;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* <p>Title : SysOptLogServiceImpl</p>
|
||||
* <p>Description : 系统操作日志 ServiceImpl</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : xujun
|
||||
* @version : 1.0.0
|
||||
* @date : 2026-06-02 16:44:47
|
||||
*/
|
||||
@Slf4j
|
||||
@Primary
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class SysOptLogServiceImpl implements SysOptLogService {
|
||||
|
||||
private final SysConfig sysConfig;
|
||||
|
||||
private final SysOptLogBaseService sysOptLogBaseService;
|
||||
|
||||
private final SysOptLogConvert sysOptLogConvert;
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
*
|
||||
* @param pageReq 分页请求
|
||||
* @return 分页结果
|
||||
*/
|
||||
@Override
|
||||
public Result<PageResp<SysOptLogResp>> page(PageReq<SysOptLogPageReq> pageReq) {
|
||||
// 分页查询
|
||||
Page<SysOptLog> page = getPageData(pageReq.getCurrentPage(), pageReq.getPageSize(), pageReq.getQuery());
|
||||
// 分装结果
|
||||
PageResp<SysOptLogResp> pageResp = new PageResp<>(pageReq, page.getTotal(), sysOptLogConvert.entityToRespList(page.getRecords()));
|
||||
return Result.ok(pageResp);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存日志
|
||||
*
|
||||
* @param traceId 日志追踪 ID
|
||||
* @param logData 日志
|
||||
*/
|
||||
@Override
|
||||
public void save(String traceId, JSONObject logData) {
|
||||
// 忽略操作日志
|
||||
List<String> ignoreOptLog = sysConfig.getLog().getIgnoreOptLog();
|
||||
|
||||
OptLogDto dto = logData.toJavaObject(OptLogDto.class);
|
||||
String uri = dto.getUri();
|
||||
|
||||
// 判断忽略操作日志
|
||||
if (PathPatternUtils.match(ignoreOptLog, uri)) {
|
||||
return;
|
||||
}
|
||||
|
||||
dto.setTraceId(traceId);
|
||||
SysOptLog optLog = sysOptLogConvert.dtoToEntity(dto);
|
||||
String ip = optLog.getIp();
|
||||
if (StringUtils.isNotBlank(ip)) {
|
||||
try {
|
||||
IpAddrDto ipAddr = IpUtils.search(ip);
|
||||
optLog.setAddr(IpUtils.searchAddr(ipAddr));
|
||||
optLog.setAddrCode(IpUtils.getCode(ipAddr));
|
||||
} catch (Exception e) {
|
||||
log.warn("获取 IP 地址信息失败,IP = {}", ip);
|
||||
}
|
||||
}
|
||||
sysOptLogBaseService.save(optLog);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出 Excel
|
||||
*
|
||||
* @param req 请求参数
|
||||
* @return Excel 数据
|
||||
*/
|
||||
@Override
|
||||
public List<SysOptLogExcel> exportExcel(SysOptLogPageReq req) {
|
||||
// 创建查询条件
|
||||
LambdaQueryWrapper<SysOptLog> query = new LambdaQueryWrapper<>();
|
||||
// 查询字段
|
||||
query.select(
|
||||
SysOptLog::getTraceId
|
||||
, SysOptLog::getTitle
|
||||
, SysOptLog::getAccountId
|
||||
, SysOptLog::getAccount
|
||||
, SysOptLog::getIp
|
||||
, SysOptLog::getAddr
|
||||
, SysOptLog::getUri
|
||||
, SysOptLog::getMemo
|
||||
, SysOptLog::getGmtCreate
|
||||
);
|
||||
// 设置查询条件
|
||||
setQueryWrapper(query, req);
|
||||
// 排序
|
||||
query.orderByDesc(SysOptLog::getGmtCreate);
|
||||
List<SysOptLog> dataList = sysOptLogBaseService.list(query);
|
||||
return dataList.stream().map(sysOptLogConvert::entityToExcel).toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取分页数据
|
||||
*
|
||||
* @param currentPage 当前页
|
||||
* @param pageSize 每页数量
|
||||
* @param req 请求参数
|
||||
* @return 分页数据
|
||||
*/
|
||||
private Page<SysOptLog> getPageData(Integer currentPage, Integer pageSize, SysOptLogPageReq req) {
|
||||
// 创建查询条件
|
||||
LambdaQueryWrapper<SysOptLog> query = new LambdaQueryWrapper<>();
|
||||
// 查询字段
|
||||
query.select(
|
||||
SysOptLog::getId
|
||||
, SysOptLog::getTraceId
|
||||
, SysOptLog::getTitle
|
||||
, SysOptLog::getAccountId
|
||||
, SysOptLog::getAccount
|
||||
, SysOptLog::getIp
|
||||
, SysOptLog::getAddr
|
||||
, SysOptLog::getAddrCode
|
||||
, SysOptLog::getUri
|
||||
, SysOptLog::getMemo
|
||||
, SysOptLog::getGmtCreate
|
||||
);
|
||||
// 设置查询条件
|
||||
setQueryWrapper(query, req);
|
||||
// 排序
|
||||
query.orderByDesc(SysOptLog::getGmtCreate);
|
||||
return sysOptLogBaseService.page(QueryUtils.getPage(currentPage, pageSize), query);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置查询条件
|
||||
*
|
||||
* @param query 查询条件
|
||||
* @param req 请求参数
|
||||
*/
|
||||
private void setQueryWrapper(LambdaQueryWrapper<SysOptLog> query, SysOptLogPageReq req) {
|
||||
if (Objects.isNull(req)) {
|
||||
return;
|
||||
}
|
||||
// 查询条件
|
||||
query.eq(Objects.nonNull(req.getId()), SysOptLog::getId, req.getId());
|
||||
query.like(StringUtils.isNotBlank(req.getTraceId()), SysOptLog::getTraceId, req.getTraceId());
|
||||
query.like(StringUtils.isNotBlank(req.getTitle()), SysOptLog::getTitle, req.getTitle());
|
||||
query.eq(Objects.nonNull(req.getAccountId()), SysOptLog::getAccountId, req.getAccountId());
|
||||
query.like(StringUtils.isNotBlank(req.getAccount()), SysOptLog::getAccount, req.getAccount());
|
||||
query.like(StringUtils.isNotBlank(req.getIp()), SysOptLog::getIp, req.getIp());
|
||||
query.like(StringUtils.isNotBlank(req.getAddr()), SysOptLog::getAddr, req.getAddr());
|
||||
query.like(StringUtils.isNotBlank(req.getAddrCode()), SysOptLog::getAddrCode, req.getAddrCode());
|
||||
query.like(StringUtils.isNotBlank(req.getUri()), SysOptLog::getUri, req.getUri());
|
||||
query.like(StringUtils.isNotBlank(req.getMemo()), SysOptLog::getMemo, req.getMemo());
|
||||
QueryUtils.addTimeRange(query, req.getGmtCreateRange(), SysOptLog::getGmtCreate);
|
||||
}
|
||||
|
||||
}
|
||||
42
xtools-app-sys/xtools-app-sys-tag/pom.xml
Normal file
42
xtools-app-sys/xtools-app-sys-tag/pom.xml
Normal file
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.xujun</groupId>
|
||||
<artifactId>xtools-app-sys</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
<artifactId>xtools-app-sys-tag</artifactId>
|
||||
|
||||
<!-- 依赖 -->
|
||||
<dependencies>
|
||||
<!-- xtools begin -->
|
||||
<!-- xtools-boot-base -->
|
||||
<dependency>
|
||||
<groupId>org.xujun</groupId>
|
||||
<artifactId>xtools-boot-core</artifactId>
|
||||
</dependency>
|
||||
<!-- xtools end -->
|
||||
|
||||
<!-- spring begin -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
</dependency>
|
||||
<!-- spring end -->
|
||||
|
||||
<!-- jakarta -->
|
||||
<dependency>
|
||||
<groupId>jakarta.annotation</groupId>
|
||||
<artifactId>jakarta.annotation-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
<artifactId>jakarta.servlet-api</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,39 @@
|
||||
package xtools.app.sys.tag.config;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
import xtools.app.sys.tag.interceptor.SwaggerTagInterceptor;
|
||||
import xtools.base.config.BaseParams;
|
||||
|
||||
/**
|
||||
* <p>Title : WebMvcSwaggerConfig</p>
|
||||
* <p>Description : WebMvcSwaggerConfig</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 1.0.0
|
||||
* @date : 2026/6/2 16:44:47
|
||||
*/
|
||||
@Configuration
|
||||
public class WebMvcSwaggerConfig implements WebMvcConfigurer, BaseParams {
|
||||
|
||||
@Resource
|
||||
private SwaggerTagInterceptor swaggerTagInterceptor;
|
||||
|
||||
/**
|
||||
* 添加拦截器
|
||||
*
|
||||
* @param registry 注册器
|
||||
*/
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(swaggerTagInterceptor)
|
||||
.addPathPatterns("/**")
|
||||
.order(CP_NUM0);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package xtools.app.sys.tag.interceptor;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import xtools.base.config.BaseParams;
|
||||
import xtools.boot.api.constant.BootCommonConstant;
|
||||
import xtools.boot.core.holder.CommonHolder;
|
||||
import xtools.core.StringUtils;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
/**
|
||||
* <p>Title : SwaggerTagInterceptor</p>
|
||||
* <p>Description : SwaggerTagInterceptor</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* <p>Version : 1.0.0</p>
|
||||
* @date : 2026/6/3 17:28
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class SwaggerTagInterceptor implements HandlerInterceptor, BootCommonConstant, BaseParams {
|
||||
|
||||
/**
|
||||
* 进入Handler方法之前执行
|
||||
*
|
||||
* @param request HttpServletRequest
|
||||
* @param response HttpServletResponse
|
||||
* @param handler handler
|
||||
* @return true(放行) or false(拦截)
|
||||
*/
|
||||
@Override
|
||||
public boolean preHandle(
|
||||
@NonNull HttpServletRequest request,
|
||||
@NonNull HttpServletResponse response,
|
||||
@NonNull Object handler
|
||||
) {
|
||||
if (!(handler instanceof HandlerMethod handlerMethod)) {
|
||||
return true;
|
||||
}
|
||||
Object get = CommonHolder.get(GET_SWAGGER_TAG);
|
||||
if (Objects.isNull(get)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
StringJoiner joiner = new StringJoiner(CP_LINE);
|
||||
// 获取@Tag注解
|
||||
Tag tag = handlerMethod.getBeanType().getAnnotation(Tag.class);
|
||||
if (Objects.nonNull(tag)) {
|
||||
String name = tag.name();
|
||||
if (StringUtils.isNotBlank(name)) {
|
||||
joiner.add(name);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取@Operation注解
|
||||
Operation operation = handlerMethod.getMethodAnnotation(Operation.class);
|
||||
if (Objects.nonNull(operation)) {
|
||||
String summary = operation.summary();
|
||||
if (StringUtils.isNotBlank(summary)) {
|
||||
joiner.add(summary);
|
||||
}
|
||||
}
|
||||
CommonHolder.set(SWAGGER_TAG, joiner.toString());
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user