feat: 初始化

This commit is contained in:
2024-04-09 11:34:46 +08:00
commit 39f3acc15f
3209 changed files with 253442 additions and 0 deletions
@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>febs-common</artifactId>
<groupId>com.yida.data</groupId>
<version>2.2-RELEASE</version>
</parent>
<groupId>com.yida.data</groupId>
<artifactId>febs-common-log-starter</artifactId>
<name>core-operation-log</name>
<description>febs-common-log-starter</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- aop -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>com.yida.data</groupId>
<artifactId>febs-common-core</artifactId>
<version>${febs-cloud.version}</version>
</dependency>
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>${logstash-logback-encoder.version}</version>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,40 @@
package com.yida.data.log.annotation;
import com.yida.data.common.core.common.ModuleName;
import com.yida.data.common.core.entity.system.enums.OperationLogTypeEnum;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 后台操作日志注解
*
* @author ZYJ
* @date 2021/1/7
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OperationLog {
/**
* 查询模块
*/
ModuleName module();
/**
* 方法名称
*/
String methods() default "";
/**
* 日志操作类型
*
* @see OperationLogTypeEnum
*/
OperationLogTypeEnum type() default OperationLogTypeEnum.SELECT;
}
@@ -0,0 +1,134 @@
package com.yida.data.log.aspect;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.yida.data.common.core.entity.CurrentUser;
import com.yida.data.common.core.exception.FebsException;
import com.yida.data.common.core.utils.FebsUtil;
import com.yida.data.log.service.LogService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.http.MediaType;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* 操作日志切面类
*
* @author ZYJ
* @date 2021/1/8
*/
@Aspect
@Component
@Slf4j
@EnableAsync
@RequiredArgsConstructor
public class OperationLogAspect {
private final LogService logService;
/**
* 处理操作日志数据
*
* @param joinPoint ProceedingJoinPoint类
* @return java.lang.Object
* @author ZYJ
* @date 2021/3/19 11:06
*/
@Around("@annotation(com.yida.data.log.annotation.OperationLog)")
public Object insertOperationLog(ProceedingJoinPoint joinPoint) throws Throwable {
//返回结果
Object result;
HttpServletRequest request = ((ServletRequestAttributes) Objects
.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
//请求参数
String params = getRequestParams(joinPoint, request);
//执行接口
result = joinPoint.proceed();
//异步保存日志
Long createId = null;
String createName = null;
if (FebsUtil.isLogin()) {
CurrentUser currentUser = FebsUtil.getCurrentUser();
if (currentUser != null) {
createId = currentUser.getUserId();
createName = currentUser.getUsername();
}
}
logService.saveOperationLog(joinPoint, FebsUtil.getHttpServletRequestIpAddress(), params, result, createId,
createName);
return result;
}
/**
* 获取请求参数
*
* @param joinPoint ProceedingJoinPoint类
* @param request HttpServletRequest类
* @return java.lang.String
* @author ZYJ
* @date 2021/1/11 14:21
*/
private static String getRequestParams(ProceedingJoinPoint joinPoint, HttpServletRequest request) {
//得到请求参数值
Object[] args = joinPoint.getArgs();
//获取请求头
String contentType = request.getContentType();
//判断是否为application/json请求
if (StrUtil.isNotBlank(contentType) && (MediaType.APPLICATION_JSON_VALUE.equalsIgnoreCase(contentType) || contentType
.equalsIgnoreCase(MediaType.APPLICATION_JSON_VALUE))) {
//设置请求参数
List<Object> objList = new ArrayList<>();
//循环获取参数值
for (Object arg : args) {
if (arg instanceof HttpServletRequest
|| arg instanceof HttpServletResponse
|| arg instanceof MultipartFile) {
continue;
}
objList.add(arg);
}
return JSON.toJSONString(objList);
}
//得到请求参数名称
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
String[] parameterNames = methodSignature.getParameterNames();
//返回值
JSONObject jsonObject = new JSONObject();
//循环获取参数值
for (int i = 0; i < args.length; i++) {
Object arg = args[i];
if (arg instanceof HttpServletRequest
|| arg instanceof HttpServletResponse
|| arg instanceof MultipartFile) {
continue;
}
jsonObject.put(parameterNames[i], arg);
}
return jsonObject.toJSONString();
}
}
@@ -0,0 +1,99 @@
package com.yida.data.log.configure;
import net.logstash.logback.appender.LogstashTcpSocketAppender;
import net.logstash.logback.encoder.LogstashEncoder;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.ReadingConverter;
import org.springframework.data.convert.WritingConverter;
import org.springframework.data.elasticsearch.config.ElasticsearchConfigurationSupport;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchCustomConversions;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import cn.hutool.json.JSONUtil;
@Configuration
public class ElasticsearchConfiguration extends ElasticsearchConfigurationSupport {
@Value("${spring.application.name}")
private String applicationName;
private static final LoggerContext CONTEXT;
private static final Logger ROOTLOGGER;
static {
CONTEXT = (LoggerContext) LoggerFactory.getILoggerFactory();
ROOTLOGGER = CONTEXT.getLogger("ROOT");
}
/**
* conversions for LocalDateTime
*
* @return
*/
@Bean
@Override
public ElasticsearchCustomConversions elasticsearchCustomConversions() {
List<Converter> converters = new ArrayList<>();
converters.add(DateToLocalDateTimeConverter.INSTANCE);
converters.add(LongToLocalDateTimeConverter.INSTANCE);
return new ElasticsearchCustomConversions(converters);
}
@Bean
public void enableElk() {
LogstashTcpSocketAppender appender = new LogstashTcpSocketAppender();
LogstashEncoder encoder = new LogstashEncoder();
HashMap<String, String> customFields = new HashMap<>(2);
customFields.put("application-name", applicationName);
String customFieldsString = JSONUtil.toJsonStr(customFields);
encoder.setCustomFields(customFieldsString);
appender.setEncoder(encoder);
//appender.addDestination(properties.getLogstashHost());
appender.setName("logstash[" + applicationName + "]");
appender.start();
appender.setContext(CONTEXT);
ROOTLOGGER.addAppender(appender);
}
@ReadingConverter
enum LongToLocalDateTimeConverter implements Converter<Long, LocalDateTime> {
INSTANCE;
@Override
public java.time.LocalDateTime convert(Long source) {
return Instant.ofEpochMilli(source).atZone(ZoneId.systemDefault()).toLocalDateTime();
}
}
@WritingConverter
enum DateToLocalDateTimeConverter implements Converter<Date, LocalDateTime> {
INSTANCE;
@Override
public LocalDateTime convert(Date date) {
Instant instant = date.toInstant();
return instant.atZone(ZoneId.systemDefault()).toLocalDateTime();
}
}
}
@@ -0,0 +1,155 @@
package com.yida.data.log.service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.yida.data.common.core.common.ResultBean;
import com.yida.data.common.core.entity.CurrentUser;
import com.yida.data.common.core.entity.constant.CachePrefixConstant;
import com.yida.data.common.core.entity.system.Log;
import com.yida.data.common.core.entity.system.enums.OperationLogTypeEnum;
import com.yida.data.common.core.utils.FebsUtil;
import com.yida.data.log.annotation.OperationLog;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import cc.mrbird.febs.common.redis.service.RedisService;
import cn.hutool.core.date.LocalDateTimeUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
/**
* 日志service层
*
* @author ZYJ
* @date 2021/1/8
*/
@Service
@Slf4j
@RequiredArgsConstructor
public class LogService {
private final RedisService redisService;
/**
* 保存操作日志信息
*
* @param joinPoint ProceedingJoinPoint类
* @param ip ip地址
* @param params 请求参数
* @param result 接口返回结果
* @author ZYJ
* @date 2021/1/8 16:30
*/
@Async
public void saveOperationLog(JoinPoint joinPoint, String ip, String params, Object result, Long createId, String createName) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
OperationLog opLog = method.getAnnotation(OperationLog.class);
//ip地址
Log systemLogInfo = new Log();
systemLogInfo.setCreateId(createId);
systemLogInfo.setCreateName(createName);
// 创建人
// if (FebsUtil.isLogin()) {
// CurrentUser currentUser = FebsUtil.getCurrentUser();
// if (currentUser != null) {
// systemLogInfo.setCreateId(currentUser.getUserId());
// systemLogInfo.setCreateName(currentUser.getUsername());
// }
// }
systemLogInfo.setIp(ip);
//设置开始时间
systemLogInfo.setStartTime(LocalDateTime.now());
systemLogInfo.setCreateDate(LocalDateTime.now());
try {
//设置操作模块与操作内容
OperationLogTypeEnum opType = opLog.type();
systemLogInfo.setModule(opLog.module().getName());
systemLogInfo.setMethod(opLog.methods());
//设置操作方法名称
String className = joinPoint.getTarget().getClass().getName();
String methodName = method.getName();
methodName = className + "." + methodName;
systemLogInfo.setMethodName(methodName);
//请求参数
systemLogInfo.setOperateParams(params);
//返回结果
systemLogInfo.setResult(JSON.toJSONString(result));
//将返回值转换为对象
ResultBean<Object> logResult = JSON.parseObject(JSON.toJSONString(result),
new TypeReference<ResultBean<Object>>() {
});
int successStatus = 200;
if (logResult != null) {
if (logResult.getStatus() == successStatus) {
//设置操作结果
systemLogInfo.setResultStatus(logResult.getStatus());
systemLogInfo.setResultMsg("操作成功");
} else {
//设置操作结果
systemLogInfo.setResultStatus(logResult.getStatus());
systemLogInfo.setResultMsg(logResult.getMessage());
}
}
//日志类型
systemLogInfo.setLogType(getLogType(opType.getValue(), params));
} catch (Exception e) {
log.error("设置操作日志参数失败{}: ", e.getMessage(), e);
//设置操作结果
systemLogInfo.setResultMsg(e.getMessage());
} finally {
//设置结束时间
systemLogInfo.setEndTime(LocalDateTime.now());
//操作时长
systemLogInfo.setOperationTime(LocalDateTimeUtil.between(systemLogInfo.getStartTime(),
systemLogInfo.getEndTime(), ChronoUnit.MILLIS));
//保存数据到redis list数据
redisService.lSet(CachePrefixConstant.OPERATION_LOG_LIST, systemLogInfo);
}
}
/**
* 获取操作日志类型
*
* @param value 日志类型枚举值
* @param params 请求参数
* @return java.lang.String
* @author ZYJ
* @date 2021/1/11 10:52
*/
private String getLogType(String value, String params) {
try {
//当为保存类型时
if (OperationLogTypeEnum.SAVE.getValue().equals(value)) {
//当为保存时, 请求参数被封装成了数组
JSONArray jsonArray = JSON.parseArray(params);
//获取第一个参数
JSONObject jsonObject = jsonArray.getJSONObject(0);
if (jsonObject != null) {
String id = jsonObject.getString("id");
//判断id值
if (StringUtils.isNotBlank(id)) {
value = OperationLogTypeEnum.UPDATE.getValue();
} else {
value = OperationLogTypeEnum.INSERT.getValue();
}
}
}
return value;
} catch (Exception e) {
log.error("判断日志类型失败{}: ", e.getMessage(), e);
return value;
}
}
}
@@ -0,0 +1,5 @@
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.yida.data.log.aspect.OperationLogAspect,\
com.yida.data.log.service.LogService,\
com.yida.data.log.configure.ElasticsearchConfiguration
@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<springProperty scope="context" name="springAppName" source="spring.application.name"/>
<property name="log.path" value="../log/${springAppName}"/>
<property name="log.maxHistory" value="15"/>
<property name="log.colorPattern"
value="%magenta(%d{yyyy-MM-dd HH:mm:ss}) %highlight(%-5level) %boldCyan(${springAppName:-}) %yellow(%thread) %green(%logger) %msg%n"/>
<property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5level ${springAppName:-} %thread %logger %msg%n"/>
<!--输出到控制台-->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.colorPattern}</pattern>
</encoder>
</appender>
<!--输出到文件-->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/info/info.%d{yyyy-MM-dd}.log</fileNamePattern>
<MaxHistory>${log.maxHistory}</MaxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/error/error.%d{yyyy-MM-dd}.log</fileNamePattern>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<root level="debug">
<appender-ref ref="console"/>
</root>
<root level="info">
<appender-ref ref="file_info"/>
<appender-ref ref="file_error"/>
</root>
</configuration>