以下是基于springboot+springcloud实现的操作日志功能
第一步:定义日志注解SysLog
/**
* 操作日志注解
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysLog {
/**
* 日志描述
*/
String desc() default "";
/**
* 日志操作类型
*/
BusinessType businessType() default BusinessType.OTHER;
}
第二步:配置日志切面记录日志信息
/**
* 操作日志切面
*/
@Slf4j
@Aspect
@Component
public class WebLogAspect {
@Autowired
private LogFeignClient logFeignClient;
/**
* 日志 切面 自定义注解 切到任意方法
*/
@Pointcut("@annotation(com.yuguo.aspect.SysLog)")
public void webLog() {
}
@Before("webLog()")
public void doBefore(JoinPoint joinPoint) {
log.info("dobefore...");
}
@AfterReturning(returning = "ret", pointcut = "webLog()")
public void doAfterReturning(JoinPoint joinPoint, Object ret) throws Throwable {
// 处理完请求,返回内容
log.info("doAfter save log ...");
try {
//获取请求数据
Map<String, Object> logMap = getLogData(joinPoint);
logFeignClient.saveLog(logMap);
} catch (Exception e) {
log.error("##########[WebLogAspect]catch exception, save log error!###########" + e.getMessage());
}
}
//获取请求数据
private Map<String, Object> getLogData(JoinPoint joinPoint) {
Map<String, Object> logMap = new HashMap<String, Object>();
try {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
//日志描述 日志类型
String methodName = joinPoint.getSignature().getName();
Method method = currentMethod(joinPoint, methodName);
SysLog sysLog = method.getAnnotation(SysLog.class);
String eventDesc = sysLog.desc();
BusinessType bType = sysLog.businessType();
String eventType = BusinessType.getMsg(bType);
logMap.put("eventDesc", eventDesc);
logMap.put("eventType", eventType);
// 请求地址
String requestUrl = request.getRequestURL().toString();
logMap.put("requestUrl", requestUrl);
//客户端地址
//String requestIp = request.getRemoteAddr();
String clientIp = getClientIp (request);
logMap.put("requestIp", clientIp);
//操作者
String operator = request.getRemoteUser();
logMap.put("operator", operator);
//请求参数
String requestParam = null;
Enumeration<String> enu = request.getParameterNames();
while (enu.hasMoreElements()) {
String name = (String) enu.nextElement();
requestParam = requestParam + name + ":" + request.getParameter(name) + ",";
log.info("name【请求参数名】:{},value【请求参数值】:{}", name, request.getParameter(name));
}
//如果为空,就从请求体里面去获取
if (StringUtils.isBlank(requestParam)) {
log.info("requestParam:" + requestParam + ",再从请求体中获取");
Object[] objects = joinPoint.getArgs();
requestParam = JSONObject.toJSONString(objects);
}
log.info("REQUEST_PARAM【请求参数】 : " + requestParam);
logMap.put("requestParam", requestParam);
// 测试另一种获取请求参数的方式:
String paramData = JSON.toJSONString(request.getParameterMap(),
SerializerFeature.DisableCircularReferenceDetect, SerializerFeature.WriteMapNullValue);
log.info("######测试得到的requestParam:"+paramData+"######");
} catch (Exception e) {
log.error("####[WebLogAspect]catch exception, getLogData log error! 组装数据错误 #####" + e.getMessage());
}
return logMap;
}
private Method currentMethod(JoinPoint joinPoint, String methodName) {
Method[] methods = joinPoint.getTarget().getClass().getMethods();
Method resultMethod = null;
for (Method method : methods) {
if (method.getName().equals(methodName)) {
resultMethod = method;
break;
}
}
return resultMethod;
}
/**
* 获取客户端ip地址
* @param request
* @return
*/
public static String getClientIp(HttpServletRequest request)
{
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.trim() == "" || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.trim() == "" || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.trim() == "" || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
// 多个路由时,取第一个非unknown的ip
final String[] arr = ip.split(",");
for (final String str : arr) {
if (!"unknown".equalsIgnoreCase(str)) {
ip = str;
break;
}
}
return ip;
}
}
第三步:定义功能类型BusinessType
/**
* 日志操作类型
*/
public enum BusinessType
{
/**
* 其它
*/
OTHER,
/**
* 新增
*/
INSERT,
/**
* 修改
*/
UPDATE,
/**
* 删除
*/
DELETE,
/**
* 查询
*/
SELECT,
/**
* 导出
*/
EXPORT,
/**
* 导入
*/
IMPORT;
public static String getMsg(BusinessType type){
String result = null;
switch (type) {
case INSERT:
result = "新增";
break;
case UPDATE:
result = "修改";
break;
case DELETE:
result = "删除";
break;
case SELECT:
result = "查询";
break;
case EXPORT:
result = "导出";
break;
case IMPORT:
result = "导入";
break;
case OTHER:
result = "其它";
break;
default:
break;
}
return result;
}
}
第四步:方法上添加日志注解@SysLog()
@PostMapping
@SysLog(desc = "新增用户", businessType = BusinessType.INSERT)
public Result add(User user){
...
}