perf: 优化系统日志参数获取,优化在线用户Token管理,优化SQl日志打印

This commit is contained in:
Jie Zheng 2025-01-18 17:48:37 +08:00
parent 1f54a5425f
commit 25e5b553e0
10 changed files with 78 additions and 40 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
### IDEA ###
.idea/*
.DS_Store
application.pid

View File

@ -23,6 +23,8 @@
<!--表格渲染--> <!--表格渲染-->
<el-table ref="table" v-loading="crud.loading" :data="crud.data" style="width: 100%;" @selection-change="crud.selectionChangeHandler"> <el-table ref="table" v-loading="crud.loading" :data="crud.data" style="width: 100%;" @selection-change="crud.selectionChangeHandler">
<el-table-column type="selection" width="55" /> <el-table-column type="selection" width="55" />
<el-table-column :show-overflow-tooltip="true" prop="uid" label="会话编号" />
<el-table-column prop="userName" label="用户名" /> <el-table-column prop="userName" label="用户名" />
<el-table-column prop="nickName" label="用户昵称" /> <el-table-column prop="nickName" label="用户昵称" />
<el-table-column prop="dept" label="部门" /> <el-table-column prop="dept" label="部门" />

1
eladmin/.gitignore vendored
View File

@ -1,4 +1,5 @@
### IDEA ### ### IDEA ###
.DS_Store
~/* ~/*
.idea/* .idea/*
*.iml *.iml

View File

@ -32,7 +32,6 @@ import java.util.*;
* 字符串工具类, 继承org.apache.commons.lang3.StringUtils类 * 字符串工具类, 继承org.apache.commons.lang3.StringUtils类
*/ */
@Slf4j @Slf4j
@SuppressWarnings({"all"})
public class StringUtils extends org.apache.commons.lang3.StringUtils { public class StringUtils extends org.apache.commons.lang3.StringUtils {
private static final char SEPARATOR = '_'; private static final char SEPARATOR = '_';
@ -133,13 +132,13 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
*/ */
public static String getIp(HttpServletRequest request) { public static String getIp(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for"); String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) { if (ip == null || ip.isEmpty() || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP"); ip = request.getHeader("Proxy-Client-IP");
} }
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) { if (ip == null || ip.isEmpty() || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP"); ip = request.getHeader("WL-Proxy-Client-IP");
} }
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) { if (ip == null || ip.isEmpty() || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr(); ip = request.getRemoteAddr();
} }
String comma = ","; String comma = ",";
@ -169,6 +168,9 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
return null; return null;
} }
/**
* 获取浏览器
*/
public static String getBrowser(HttpServletRequest request) { public static String getBrowser(HttpServletRequest request) {
UserAgent ua = UserAgentUtil.parse(request.getHeader("User-Agent")); UserAgent ua = UserAgentUtil.parse(request.getHeader("User-Agent"));
String browser = ua.getBrowser().toString() + " " + ua.getVersion(); String browser = ua.getBrowser().toString() + " " + ua.getVersion();
@ -230,6 +232,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
} }
} }
@SuppressWarnings({"all"})
public static List<Field> getAllFields(Class clazz, List<Field> fields) { public static List<Field> getAllFields(Class clazz, List<Field> fields) {
if (clazz != null) { if (clazz != null) {
fields.addAll(Arrays.asList(clazz.getDeclaredFields())); fields.addAll(Arrays.asList(clazz.getDeclaredFields()));

View File

@ -88,6 +88,10 @@ public class LogAspect {
sysLogService.save(getUsername(), StringUtils.getBrowser(request), StringUtils.getIp(request), (ProceedingJoinPoint)joinPoint, sysLog); sysLogService.save(getUsername(), StringUtils.getBrowser(request), StringUtils.getIp(request), (ProceedingJoinPoint)joinPoint, sysLog);
} }
/**
* 获取用户名
* @return /
*/
public String getUsername() { public String getUsername() {
try { try {
return SecurityUtils.getCurrentUsername(); return SecurityUtils.getCurrentUsername();

View File

@ -32,8 +32,8 @@ import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@ -47,7 +47,10 @@ import java.util.*;
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
public class SysLogServiceImpl extends ServiceImpl<SysLogMapper, SysLog> implements SysLogService { public class SysLogServiceImpl extends ServiceImpl<SysLogMapper, SysLog> implements SysLogService {
private final SysLogMapper sysLogMapper; private final SysLogMapper sysLogMapper;
// 定义敏感字段常量数组
private static final String[] SENSITIVE_KEYS = {"password"};
@Override @Override
public PageResult<SysLog> queryAll(SysLogQueryCriteria criteria, Page<SysLog> page) { public PageResult<SysLog> queryAll(SysLogQueryCriteria criteria, Page<SysLog> page) {
@ -71,6 +74,8 @@ public class SysLogServiceImpl extends ServiceImpl<SysLogMapper, SysLog> impleme
if (sysLog == null) { if (sysLog == null) {
throw new IllegalArgumentException("Log 不能为 null!"); throw new IllegalArgumentException("Log 不能为 null!");
} }
// 获取方法签名
MethodSignature signature = (MethodSignature) joinPoint.getSignature(); MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod(); Method method = signature.getMethod();
me.zhengjie.annotation.Log aopLog = method.getAnnotation(me.zhengjie.annotation.Log.class); me.zhengjie.annotation.Log aopLog = method.getAnnotation(me.zhengjie.annotation.Log.class);
@ -78,21 +83,23 @@ public class SysLogServiceImpl extends ServiceImpl<SysLogMapper, SysLog> impleme
// 方法路径 // 方法路径
String methodName = joinPoint.getTarget().getClass().getName() + "." + signature.getName() + "()"; String methodName = joinPoint.getTarget().getClass().getName() + "." + signature.getName() + "()";
// 描述 // 获取参数
sysLog.setDescription(aopLog.value()); JSONObject params = getParameter(method, joinPoint.getArgs());
// 填充基本信息
sysLog.setRequestIp(ip); sysLog.setRequestIp(ip);
sysLog.setAddress(StringUtils.getCityInfo(sysLog.getRequestIp())); sysLog.setAddress(StringUtils.getCityInfo(sysLog.getRequestIp()));
sysLog.setMethod(methodName); sysLog.setMethod(methodName);
sysLog.setUsername(username); sysLog.setUsername(username);
sysLog.setParams(getParameter(method, joinPoint.getArgs())); sysLog.setParams(JSON.toJSONString(params));
// 记录登录用户隐藏密码信息
if(signature.getName().equals("login") && StringUtils.isNotEmpty(sysLog.getParams())){
JSONObject obj = JSON.parseObject(sysLog.getParams());
sysLog.setUsername(obj.getString("username"));
sysLog.setParams(JSON.toJSONString(Dict.create().set("username", sysLog.getUsername())));
}
sysLog.setBrowser(browser); sysLog.setBrowser(browser);
sysLog.setDescription(aopLog.value());
// 如果没有获取到用户名尝试从参数中获取
if(StringUtils.isBlank(sysLog.getUsername())){
sysLog.setUsername(params.getString("username"));
}
// 保存 // 保存
save(sysLog); save(sysLog);
} }
@ -100,35 +107,40 @@ public class SysLogServiceImpl extends ServiceImpl<SysLogMapper, SysLog> impleme
/** /**
* 根据方法和传入的参数获取请求参数 * 根据方法和传入的参数获取请求参数
*/ */
private String getParameter(Method method, Object[] args) { private JSONObject getParameter(Method method, Object[] args) {
List<Object> argList = new ArrayList<>(); JSONObject params = new JSONObject();
Parameter[] parameters = method.getParameters(); Parameter[] parameters = method.getParameters();
for (int i = 0; i < parameters.length; i++) { for (int i = 0; i < parameters.length; i++) {
// 过滤掉不能序列化的类型: MultiPartFile // 过滤掉 MultiPartFile
if (args[i] instanceof MultipartFile) { if (args[i] instanceof MultipartFile) {
continue; continue;
} }
//将RequestBody注解修饰的参数作为请求参数 // 过滤掉 HttpServletResponse
if (args[i] instanceof HttpServletResponse) {
continue;
}
// 过滤掉 HttpServletRequest
if (args[i] instanceof HttpServletRequest) {
continue;
}
// 将RequestBody注解修饰的参数作为请求参数
RequestBody requestBody = parameters[i].getAnnotation(RequestBody.class); RequestBody requestBody = parameters[i].getAnnotation(RequestBody.class);
if (requestBody != null) { if (requestBody != null) {
argList.add(args[i]); params.putAll((JSONObject) JSON.toJSON(args[i]));
} } else {
//将RequestParam注解修饰的参数作为请求参数
RequestParam requestParam = parameters[i].getAnnotation(RequestParam.class);
if (requestParam != null) {
Map<String, Object> map = new HashMap<>(2);
String key = parameters[i].getName(); String key = parameters[i].getName();
if (!StringUtils.isEmpty(requestParam.value())) { params.put(key, args[i]);
key = requestParam.value();
}
map.put(key, args[i]);
argList.add(map);
} }
} }
if (argList.isEmpty()) { // 遍历敏感字段数组并替换值
return ""; Set<String> keys = params.keySet();
for (String key : SENSITIVE_KEYS) {
if (keys.contains(key)) {
params.put(key, "******");
}
} }
return argList.size() == 1 ? JSON.toJSONString(argList.get(0)) : JSON.toJSONString(argList); // 返回参数
return params;
} }
@Override @Override

View File

@ -18,7 +18,6 @@ package me.zhengjie.modules.security.security;
import cn.hutool.core.date.DateField; import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.IdUtil;
import cn.hutool.crypto.digest.DigestUtil;
import io.jsonwebtoken.*; import io.jsonwebtoken.*;
import io.jsonwebtoken.io.Decoders; import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys; import io.jsonwebtoken.security.Keys;
@ -49,7 +48,7 @@ public class TokenProvider implements InitializingBean {
private JwtBuilder jwtBuilder; private JwtBuilder jwtBuilder;
private final RedisUtils redisUtils; private final RedisUtils redisUtils;
private final SecurityProperties properties; private final SecurityProperties properties;
public static final String AUTHORITIES_UUID_KEY = "uuid"; public static final String AUTHORITIES_UUID_KEY = "uid";
public static final String AUTHORITIES_UID_KEY = "userId"; public static final String AUTHORITIES_UID_KEY = "userId";
@Override @Override
@ -75,7 +74,7 @@ public class TokenProvider implements InitializingBean {
// 设置用户ID // 设置用户ID
claims.put(AUTHORITIES_UID_KEY, user.getUser().getId()); claims.put(AUTHORITIES_UID_KEY, user.getUser().getId());
// 设置UUID确保每次Token不一样 // 设置UUID确保每次Token不一样
claims.put(AUTHORITIES_UUID_KEY, IdUtil.simpleUUID()); claims.put(AUTHORITIES_UUID_KEY, IdUtil.objectId());
return jwtBuilder return jwtBuilder
.setClaims(claims) .setClaims(claims)
.setSubject(user.getUsername()) .setSubject(user.getUsername())
@ -132,7 +131,16 @@ public class TokenProvider implements InitializingBean {
*/ */
public String loginKey(String token) { public String loginKey(String token) {
Claims claims = getClaims(token); Claims claims = getClaims(token);
String md5Token = DigestUtil.md5Hex(token); return properties.getOnlineKey() + claims.getSubject() + ":" + getId(token);
return properties.getOnlineKey() + claims.getSubject() + "-" + md5Token; }
/**
* 获取会话编号
* @param token /
* @return /
*/
public String getId(String token) {
Claims claims = getClaims(token);
return claims.get(AUTHORITIES_UUID_KEY, String.class);
} }
} }

View File

@ -53,11 +53,12 @@ public class OnlineUserService {
public void save(JwtUserDto jwtUserDto, String token, HttpServletRequest request){ public void save(JwtUserDto jwtUserDto, String token, HttpServletRequest request){
String dept = jwtUserDto.getUser().getDept().getName(); String dept = jwtUserDto.getUser().getDept().getName();
String ip = StringUtils.getIp(request); String ip = StringUtils.getIp(request);
String id = tokenProvider.getId(token);
String browser = StringUtils.getBrowser(request); String browser = StringUtils.getBrowser(request);
String address = StringUtils.getCityInfo(ip); String address = StringUtils.getCityInfo(ip);
OnlineUserDto onlineUserDto = null; OnlineUserDto onlineUserDto = null;
try { try {
onlineUserDto = new OnlineUserDto(jwtUserDto.getUsername(), jwtUserDto.getUser().getNickName(), dept, browser , ip, address, EncryptUtils.desEncrypt(token), new Date()); onlineUserDto = new OnlineUserDto(id, jwtUserDto.getUsername(), jwtUserDto.getUser().getNickName(), dept, browser , ip, address, EncryptUtils.desEncrypt(token), new Date());
} catch (Exception e) { } catch (Exception e) {
log.error(e.getMessage(),e); log.error(e.getMessage(),e);
} }

View File

@ -30,6 +30,9 @@ import java.util.Date;
@NoArgsConstructor @NoArgsConstructor
public class OnlineUserDto { public class OnlineUserDto {
@ApiModelProperty(value = "Token编号")
private String uid;
@ApiModelProperty(value = "用户名") @ApiModelProperty(value = "用户名")
private String userName; private String userName;

View File

@ -15,6 +15,6 @@ outagedetectioninterval=2
# 是否过滤 Log # 是否过滤 Log
filter=true filter=true
# 过滤 Log 时所排除的 sql 关键字,以逗号分隔 # 过滤 Log 时所排除的 sql 关键字,以逗号分隔
exclude=select 1 exclude=SELECT 1,INSERT INTO sys_log
# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset. # 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.
excludecategories=info,debug,result,commit,resultset excludecategories=info,debug,result,commit,resultset