init
This commit is contained in:
25
log/log-api/pom.xml
Normal file
25
log/log-api/pom.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>log</artifactId>
|
||||
<groupId>cn.fateverse</groupId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>log-api</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.fateverse</groupId>
|
||||
<artifactId>common-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.fateverse</groupId>
|
||||
<artifactId>common-swagger</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,28 @@
|
||||
package cn.fateverse.log.dubbo;
|
||||
|
||||
|
||||
import cn.fateverse.log.entity.LoginInfo;
|
||||
import cn.fateverse.log.entity.OperationLog;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Clay
|
||||
* @date 2023-02-20
|
||||
*/
|
||||
public interface DubboLogService {
|
||||
|
||||
/**
|
||||
* 批量保存日志
|
||||
*
|
||||
* @param list 需要保存的日志
|
||||
*/
|
||||
void batchSaveLog(List<OperationLog> list);
|
||||
|
||||
/**
|
||||
* 保存登录信息
|
||||
*
|
||||
* @param info 登录日志信息
|
||||
*/
|
||||
void saveLoginInfo(LoginInfo info);
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package cn.fateverse.log.entity;
|
||||
|
||||
import cn.fateverse.common.core.annotaion.EnableAutoField;
|
||||
import cn.fateverse.common.core.annotaion.GenerateId;
|
||||
import cn.fateverse.common.core.enums.GenIdEnum;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 用户登录信息
|
||||
*
|
||||
* @author Clay
|
||||
* @date 2022/11/2
|
||||
*/
|
||||
@Data
|
||||
@EnableAutoField
|
||||
public class LoginInfo implements Serializable {
|
||||
|
||||
/**
|
||||
* 访问Id
|
||||
*/
|
||||
@GenerateId(idType = GenIdEnum.SNOWFLAKE)
|
||||
private Long infoId;
|
||||
|
||||
private String uuid;
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
private String userName;
|
||||
/**
|
||||
* 登录ip
|
||||
*/
|
||||
private String ipddr;
|
||||
/**
|
||||
* 登录地点
|
||||
*/
|
||||
private String loginLocation;
|
||||
/**
|
||||
* 浏览器类型
|
||||
*/
|
||||
private String browser;
|
||||
/**
|
||||
* 操作系统
|
||||
*/
|
||||
private String os;
|
||||
/**
|
||||
* 登录状态
|
||||
*/
|
||||
private Integer state;
|
||||
/**
|
||||
* 登录信息
|
||||
*/
|
||||
private String msg;
|
||||
/**
|
||||
* 登录时间
|
||||
*/
|
||||
private Date loginTime;
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
package cn.fateverse.log.entity;
|
||||
|
||||
import cn.fateverse.common.core.annotaion.EnableAutoField;
|
||||
import cn.fateverse.common.core.annotaion.GenerateId;
|
||||
import cn.fateverse.common.core.enums.GenIdEnum;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author Clay
|
||||
* @date 2022/11/1
|
||||
*/
|
||||
@Data
|
||||
@EnableAutoField
|
||||
public class OperationLog implements Serializable {
|
||||
|
||||
/**
|
||||
* 日志主键
|
||||
*/
|
||||
@GenerateId(idType = GenIdEnum.SNOWFLAKE)
|
||||
private Long operId;
|
||||
|
||||
/**
|
||||
* 用户id
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 操作模块
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 业务类型(0其它 1新增 2修改 3删除)
|
||||
*/
|
||||
private Integer businessType;
|
||||
|
||||
/**
|
||||
* 请求方法
|
||||
*/
|
||||
private String method;
|
||||
|
||||
/**
|
||||
* 请求方式
|
||||
*/
|
||||
private String requestMethod;
|
||||
|
||||
/**
|
||||
* 操作类别(0其它 1后台用户 2手机端用户)
|
||||
*/
|
||||
private Integer operatorType;
|
||||
|
||||
/**
|
||||
* 操作人员
|
||||
*/
|
||||
private String operName;
|
||||
|
||||
/**
|
||||
* 部门名称
|
||||
*/
|
||||
private String deptName;
|
||||
|
||||
/**
|
||||
* 请求url
|
||||
*/
|
||||
private String operUrl;
|
||||
|
||||
/**
|
||||
* 操作地址
|
||||
*/
|
||||
private String operIp;
|
||||
|
||||
/**
|
||||
* 操作地点
|
||||
*/
|
||||
private String operLocation;
|
||||
|
||||
/**
|
||||
* 请求参数
|
||||
*/
|
||||
private String operParam;
|
||||
|
||||
/**
|
||||
* 返回参数
|
||||
*/
|
||||
private String jsonResult;
|
||||
|
||||
/**
|
||||
* 操作状态(0正常 1异常)
|
||||
*/
|
||||
private Integer state;
|
||||
|
||||
/**
|
||||
* 错误消息
|
||||
*/
|
||||
private String errorMsg;
|
||||
|
||||
/**
|
||||
* 异常栈信息
|
||||
*/
|
||||
private String errorStackTrace;
|
||||
|
||||
/**
|
||||
* 操作时间
|
||||
*/
|
||||
private Date operTime;
|
||||
|
||||
/**
|
||||
* 消耗时间
|
||||
*/
|
||||
private Long consumeTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package cn.fateverse.log.query;
|
||||
|
||||
import cn.fateverse.common.core.entity.QueryTime;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @Description: 日志管理->登录日志查询实体类
|
||||
* @Author: Gary
|
||||
* @DateTime:2022/11/15 20:24
|
||||
* @Version: V2.0
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("登录日志查询实体")
|
||||
public class LoginLogQuery extends QueryTime {
|
||||
|
||||
/**
|
||||
* 登录地址
|
||||
*/
|
||||
private String ipAddr;
|
||||
|
||||
/**
|
||||
* 用户名称
|
||||
*/
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 登录状态
|
||||
*/
|
||||
private String state;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package cn.fateverse.log.query;
|
||||
|
||||
import cn.fateverse.common.core.entity.QueryTime;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import lombok.Data;
|
||||
|
||||
|
||||
/**
|
||||
* @Description: 日志管理->操作日志查询实体类
|
||||
* @Author: Gary
|
||||
* @DateTime:2022/11/14 20:24
|
||||
* @Version: V2.0
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("日志查询实体")
|
||||
public class OperationLogQuery extends QueryTime {
|
||||
|
||||
/**
|
||||
* 系统模块
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 操作人员
|
||||
*/
|
||||
private String operName;
|
||||
|
||||
/**
|
||||
* 操作类型
|
||||
*/
|
||||
private Integer businessType;
|
||||
|
||||
/**
|
||||
* 操作状态
|
||||
*/
|
||||
private String state;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package cn.fateverse.log.vo;
|
||||
|
||||
import cn.fateverse.log.entity.LoginInfo;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 用户登录信息
|
||||
*
|
||||
* @author Clay
|
||||
* @date 2022/11/2
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class LoginInfoVo implements Serializable {
|
||||
|
||||
/**
|
||||
* 访问Id
|
||||
*/
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long infoId;
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
private String userName;
|
||||
/**
|
||||
* 登录ip
|
||||
*/
|
||||
private String ipddr;
|
||||
/**
|
||||
* 登录地点
|
||||
*/
|
||||
private String loginLocation;
|
||||
/**
|
||||
* 浏览器类型
|
||||
*/
|
||||
private String browser;
|
||||
/**
|
||||
* 操作系统
|
||||
*/
|
||||
private String os;
|
||||
/**
|
||||
* 登录状态
|
||||
*/
|
||||
private Integer state;
|
||||
/**
|
||||
* 登录信息
|
||||
*/
|
||||
private String msg;
|
||||
/**
|
||||
* 登录时间
|
||||
*/
|
||||
private Date loginTime;
|
||||
|
||||
|
||||
public static LoginInfoVo toLoginInfoVo(LoginInfo info) {
|
||||
LoginInfoVo vo = new LoginInfoVo();
|
||||
BeanUtils.copyProperties(info, vo);
|
||||
return vo;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
package cn.fateverse.log.vo;
|
||||
|
||||
import cn.fateverse.log.entity.OperationLog;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author Clay
|
||||
* @date 2022/11/1
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class OperationLogVo implements Serializable {
|
||||
|
||||
/**
|
||||
* 日志主键
|
||||
*/
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long operId;
|
||||
|
||||
/**
|
||||
* 操作模块
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 业务类型(0其它 1新增 2修改 3删除)
|
||||
*/
|
||||
private Integer businessType;
|
||||
|
||||
/**
|
||||
* 请求方法
|
||||
*/
|
||||
private String method;
|
||||
|
||||
/**
|
||||
* 请求方式
|
||||
*/
|
||||
private String requestMethod;
|
||||
|
||||
/**
|
||||
* 操作类别(0其它 1后台用户 2手机端用户)
|
||||
*/
|
||||
private Integer operatorType;
|
||||
|
||||
/**
|
||||
* 操作人员
|
||||
*/
|
||||
private String operName;
|
||||
|
||||
/**
|
||||
* 请求url
|
||||
*/
|
||||
private String operUrl;
|
||||
|
||||
/**
|
||||
* 操作地址
|
||||
*/
|
||||
private String operIp;
|
||||
|
||||
/**
|
||||
* 操作地点
|
||||
*/
|
||||
private String operLocation;
|
||||
|
||||
/**
|
||||
* 请求参数
|
||||
*/
|
||||
private String operParam;
|
||||
|
||||
/**
|
||||
* 返回参数
|
||||
*/
|
||||
private String jsonResult;
|
||||
|
||||
/**
|
||||
* 操作状态(0正常 1异常)
|
||||
*/
|
||||
private Integer state;
|
||||
|
||||
/**
|
||||
* 错误消息
|
||||
*/
|
||||
private String errorMsg;
|
||||
|
||||
/**
|
||||
* 异常栈信息
|
||||
*/
|
||||
private String errorStackTrace;
|
||||
|
||||
/**
|
||||
* 操作时间
|
||||
*/
|
||||
private Date operTime;
|
||||
|
||||
/**
|
||||
* 消耗时间
|
||||
*/
|
||||
private Long consumeTime;
|
||||
|
||||
|
||||
public static OperationLogVo toOperationLogVo(OperationLog operationLog) {
|
||||
return OperationLogVo.builder()
|
||||
.operId(operationLog.getOperId())
|
||||
.title(operationLog.getTitle())
|
||||
.businessType(operationLog.getBusinessType())
|
||||
.method(operationLog.getMethod())
|
||||
.requestMethod(operationLog.getRequestMethod())
|
||||
.operatorType(operationLog.getOperatorType())
|
||||
.operName(operationLog.getOperName())
|
||||
.operUrl(operationLog.getOperUrl())
|
||||
.operIp(operationLog.getOperIp())
|
||||
.operLocation(operationLog.getOperLocation())
|
||||
.operParam(operationLog.getOperParam())
|
||||
.jsonResult(operationLog.getJsonResult())
|
||||
.state(operationLog.getState())
|
||||
.errorMsg(operationLog.getErrorMsg())
|
||||
.operTime(operationLog.getOperTime())
|
||||
.consumeTime(operationLog.getConsumeTime())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
93
log/log-biz/pom.xml
Normal file
93
log/log-biz/pom.xml
Normal file
@@ -0,0 +1,93 @@
|
||||
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>log</artifactId>
|
||||
<groupId>cn.fateverse</groupId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>log-biz</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
<sharding.version>4.0.0-RC1</sharding.version>
|
||||
<maven.deploy.skip>true</maven.deploy.skip>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.fateverse</groupId>
|
||||
<artifactId>common-mybatis</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.fateverse</groupId>
|
||||
<artifactId>common-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.fateverse</groupId>
|
||||
<artifactId>log-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.fateverse</groupId>
|
||||
<artifactId>common-decrypt</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>1.3.2</version>
|
||||
</dependency>
|
||||
<!-- Sharding-JDBC -->
|
||||
<dependency>
|
||||
<groupId>org.apache.shardingsphere</groupId>
|
||||
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
|
||||
<version>${sharding.version}</version>
|
||||
</dependency>
|
||||
<!-- ip2region -->
|
||||
<dependency>
|
||||
<groupId>org.lionsoul</groupId>
|
||||
<artifactId>ip2region</artifactId>
|
||||
<version>2.7.0</version>
|
||||
</dependency>
|
||||
<!--rabbitmq-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-amqp</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.xml.bind</groupId>
|
||||
<artifactId>jakarta.xml.bind-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jaxb</groupId>
|
||||
<artifactId>jaxb-runtime</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>30.1-jre</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<version>2.7.3</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,22 @@
|
||||
package cn.fateverse.log;
|
||||
|
||||
import cn.fateverse.common.security.annotation.EnableSecurity;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||
|
||||
/**
|
||||
* @author Clay
|
||||
* @date 2023-05-24
|
||||
*/
|
||||
@EnableSecurity
|
||||
@EnableDiscoveryClient
|
||||
@SpringBootApplication
|
||||
public class LogApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(LogApplication.class, args);
|
||||
System.out.println("日志服务启动成功");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package cn.fateverse.log.configuration;
|
||||
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import org.springframework.boot.jdbc.metadata.DataSourcePoolMetadata;
|
||||
import org.springframework.boot.jdbc.metadata.DataSourcePoolMetadataProvider;
|
||||
import org.springframework.boot.jdbc.metadata.HikariDataSourcePoolMetadata;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
|
||||
/**
|
||||
* @author Clay
|
||||
* @date 2023-05-25
|
||||
*/
|
||||
@Configuration
|
||||
public class DataSourceHealthConfig {
|
||||
|
||||
|
||||
/**
|
||||
* 配置数据源池元数据提供者
|
||||
*
|
||||
* @return 数据源池元数据提供者
|
||||
*/
|
||||
@Bean
|
||||
DataSourcePoolMetadataProvider dataSourcePoolMetadataProvider() {
|
||||
return dataSource -> dataSource instanceof HikariDataSource
|
||||
// 如果使用的数据源没有对应的 DataSourcePoolMetadata 实现的话也可以全部使用 NotAvailableDataSourcePoolMetadata
|
||||
? new HikariDataSourcePoolMetadata((HikariDataSource) dataSource)
|
||||
: new NotAvailableDataSourcePoolMetadata();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 不可用的数据源池元数据.
|
||||
*/
|
||||
private static class NotAvailableDataSourcePoolMetadata implements DataSourcePoolMetadata {
|
||||
@Override
|
||||
public Float getUsage() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getActive() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getMax() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getMin() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValidationQuery() {
|
||||
// 该字符串是适用于MySQL的简单查询语句,用于检查检查,其他数据库可能需要更换
|
||||
return "select 1";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean getDefaultAutoCommit() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package cn.fateverse.log.configuration;
|
||||
|
||||
|
||||
import cn.fateverse.common.core.utils.ObjectUtils;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
@ConfigurationProperties(prefix = "log")
|
||||
public class RabbitProperties {
|
||||
|
||||
/**
|
||||
* 交换机名称
|
||||
*/
|
||||
public String exchangeLog = "exchange.log";
|
||||
|
||||
/**
|
||||
* 队列名称
|
||||
*/
|
||||
private String queueLog = "queue.log";
|
||||
|
||||
/**
|
||||
* 路由
|
||||
*/
|
||||
public String routingKey = "log.routing";
|
||||
|
||||
public String getExchangeLog() {
|
||||
return exchangeLog;
|
||||
}
|
||||
|
||||
public void setExchangeLog(String exchangeLog) {
|
||||
if (!ObjectUtils.isEmpty(exchangeLog)) {
|
||||
this.exchangeLog = exchangeLog;
|
||||
}
|
||||
}
|
||||
|
||||
public String getQueueLog() {
|
||||
return queueLog;
|
||||
}
|
||||
|
||||
public void setQueueLog(String queueLog) {
|
||||
if (!ObjectUtils.isEmpty(queueLog)) {
|
||||
this.queueLog = queueLog;
|
||||
}
|
||||
}
|
||||
|
||||
public String getRoutingKey() {
|
||||
return routingKey;
|
||||
}
|
||||
|
||||
public void setRoutingKey(String routingKey) {
|
||||
if (!ObjectUtils.isEmpty(routingKey)) {
|
||||
this.routingKey = routingKey;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package cn.fateverse.log.configuration;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
|
||||
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* @author Clay
|
||||
* @date 2023-05-25
|
||||
*/
|
||||
public class TablePreciseShardingAlgorithm implements PreciseShardingAlgorithm<Long> {
|
||||
/**
|
||||
* 执行分片操作
|
||||
*
|
||||
* @param tableNames 表名集合
|
||||
* @param preciseShardingValue 精确分片值
|
||||
* @return 分片后的表名
|
||||
*/
|
||||
@Override
|
||||
public String doSharding(Collection<String> tableNames, PreciseShardingValue<Long> preciseShardingValue) {
|
||||
BigDecimal bigDecimal = new BigDecimal(preciseShardingValue.getValue());
|
||||
long value = bigDecimal.divide(new BigDecimal(10), 0, RoundingMode.DOWN).longValue();
|
||||
int index = Convert.toInt(value & 1);
|
||||
List<String> list = new ArrayList<>(tableNames);
|
||||
return list.get(index);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package cn.fateverse.log.controller;
|
||||
|
||||
import cn.fateverse.common.core.result.Result;
|
||||
import cn.fateverse.common.core.result.page.TableDataInfo;
|
||||
import cn.fateverse.common.decrypt.annotation.Encrypt;
|
||||
import cn.fateverse.common.security.annotation.Anonymity;
|
||||
import cn.fateverse.log.query.LoginLogQuery;
|
||||
import cn.fateverse.log.service.LoginInfoService;
|
||||
import cn.fateverse.log.vo.LoginInfoVo;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
|
||||
/**
|
||||
* @author Clay
|
||||
* @date 2022/11/2
|
||||
*/
|
||||
@Api(tags = "登录日志管理")
|
||||
@Anonymity
|
||||
@RestController
|
||||
@RequestMapping("/login-info")
|
||||
public class LoginInfoController {
|
||||
|
||||
private final LoginInfoService loginInfoService;
|
||||
|
||||
|
||||
public LoginInfoController(LoginInfoService loginInfoService) {
|
||||
this.loginInfoService = loginInfoService;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询登录日志信息
|
||||
* @param loginLogQuery
|
||||
* @return
|
||||
*/
|
||||
|
||||
@GetMapping("/list")
|
||||
@ApiOperation("查询日志信息")
|
||||
@PreAuthorize("@ss.hasPermission('admin:log:list')")
|
||||
public Result<TableDataInfo<LoginInfoVo>> loginSearch(LoginLogQuery loginLogQuery){
|
||||
TableDataInfo<LoginInfoVo> dataTable = loginInfoService.search(loginLogQuery);
|
||||
return Result.ok(dataTable);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除登录日志 单个/批量
|
||||
* @param infoIds
|
||||
* @return
|
||||
*/
|
||||
@DeleteMapping("/{infoIds}")
|
||||
@ApiOperation("登录日志删除")
|
||||
@PreAuthorize("@ss.hasPermission('admin:log:del')")
|
||||
public Result<Void> loginRemove(@PathVariable Long[] infoIds){
|
||||
if (infoIds.length==0){
|
||||
return Result.error("id不能为空");
|
||||
}
|
||||
loginInfoService.delete(infoIds);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据id 查询日志详细信息
|
||||
* @param infoId
|
||||
* @return
|
||||
*/
|
||||
@Encrypt
|
||||
@GetMapping("/{infoId}")
|
||||
@ApiOperation("查询登录日志")
|
||||
@PreAuthorize("@ss.hasPermission('admin:log:query')")
|
||||
public Result<LoginInfoVo> getInfo(@PathVariable("infoId") Long infoId){
|
||||
LoginInfoVo loginInfo = loginInfoService.select(infoId);
|
||||
return Result.ok(loginInfo);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package cn.fateverse.log.controller;
|
||||
|
||||
import cn.fateverse.common.core.result.Result;
|
||||
import cn.fateverse.common.core.result.page.TableDataInfo;
|
||||
import cn.fateverse.common.security.annotation.Anonymity;
|
||||
import cn.fateverse.log.query.OperationLogQuery;
|
||||
import cn.fateverse.log.service.OperationService;
|
||||
import cn.fateverse.log.vo.OperationLogVo;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
|
||||
/**
|
||||
* 操作日志控制器
|
||||
*
|
||||
* @author Clay
|
||||
* @date 2022/11/1
|
||||
*/
|
||||
@Api(tags = "操作日志管理")
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/log")
|
||||
public class OperationLogController {
|
||||
|
||||
private final OperationService operationService;
|
||||
|
||||
public OperationLogController(OperationService operationService) {
|
||||
this.operationService = operationService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param operationLogQuery
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
@Anonymity
|
||||
@ApiOperation("查询日志信息")
|
||||
@PreAuthorize("@ss.hasPermission('admin:log:list')")
|
||||
public Result<TableDataInfo<OperationLogVo>> SearchLog(OperationLogQuery operationLogQuery) {
|
||||
TableDataInfo<OperationLogVo> dataTable = operationService.search(operationLogQuery);
|
||||
return Result.ok(dataTable);
|
||||
}
|
||||
|
||||
@GetMapping("/{operId}")
|
||||
@ApiOperation("查询日志信息")
|
||||
@PreAuthorize("@ss.hasPermission('admin:log:list')")
|
||||
public Result<OperationLogVo> SearchLog(@PathVariable Long operId) {
|
||||
OperationLogVo operationLogVo = operationService.select(operId);
|
||||
return Result.ok(operationLogVo);
|
||||
}
|
||||
|
||||
@DeleteMapping("/{operIds}")
|
||||
@ApiOperation("操作日志删除")
|
||||
@PreAuthorize("@ss.hasPermission('admin:log:del')")
|
||||
public Result<Integer> OperationInfoRemove(@PathVariable Long[] operIds) {
|
||||
if (operIds.length == 0) {
|
||||
return Result.error("id不能为空");
|
||||
}
|
||||
operationService.delete(operIds);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package cn.fateverse.log.dubbo;
|
||||
|
||||
import cn.fateverse.log.configuration.RabbitProperties;
|
||||
import cn.fateverse.log.service.LoginInfoService;
|
||||
import cn.fateverse.log.service.OperationService;
|
||||
import cn.fateverse.log.entity.LoginInfo;
|
||||
import cn.fateverse.log.entity.OperationLog;
|
||||
import cn.fateverse.log.mq.RabbitConfig;
|
||||
import org.apache.dubbo.config.annotation.DubboService;
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* @author Clay
|
||||
* @date 2023-02-20
|
||||
*/
|
||||
@DubboService
|
||||
public class DubboLogServiceImpl implements DubboLogService {
|
||||
|
||||
private final LoginInfoService loginInfoService;
|
||||
|
||||
@Resource
|
||||
private RabbitTemplate rabbitTemplate;
|
||||
|
||||
@Resource
|
||||
private RabbitProperties properties;
|
||||
|
||||
private final OperationService operationService;
|
||||
|
||||
private final Executor executor;
|
||||
|
||||
public DubboLogServiceImpl(LoginInfoService loginInfoService, OperationService operationService, Executor executor) {
|
||||
this.loginInfoService = loginInfoService;
|
||||
this.operationService = operationService;
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void batchSaveLog(List<OperationLog> list) {
|
||||
executor.execute(()->{
|
||||
rabbitTemplate.invoke(operations -> {
|
||||
rabbitTemplate.convertAndSend(properties.getExchangeLog(), properties.getRoutingKey(), list);
|
||||
return rabbitTemplate.waitForConfirms(5000);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveLoginInfo(LoginInfo info) {
|
||||
loginInfoService.save(info);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package cn.fateverse.log.mapper;
|
||||
|
||||
|
||||
import cn.fateverse.log.entity.LoginInfo;
|
||||
import cn.fateverse.log.query.LoginLogQuery;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Clay
|
||||
* @date 2022/11/2
|
||||
*/
|
||||
public interface LoginInfoMapper {
|
||||
|
||||
/**
|
||||
* 保存登录日志信息
|
||||
*
|
||||
* @param loginInfo
|
||||
* @return
|
||||
*/
|
||||
int save(LoginInfo loginInfo);
|
||||
|
||||
/**
|
||||
* 查询登录日志
|
||||
*
|
||||
* @param loginLogQuery
|
||||
* @return
|
||||
*/
|
||||
List<LoginInfo> search(LoginLogQuery loginLogQuery);
|
||||
/**
|
||||
* 删除登录日志
|
||||
*
|
||||
* @param infoIds 日志id
|
||||
*/
|
||||
int delete(Long[] infoIds);
|
||||
|
||||
/**
|
||||
* 查询登录日志详情
|
||||
*
|
||||
* @param infoId 日志id
|
||||
* @return 日志详情
|
||||
*/
|
||||
LoginInfo selectById(@Param("infoId") Long infoId);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package cn.fateverse.log.mapper;
|
||||
|
||||
|
||||
import cn.fateverse.common.core.entity.PageInfo;
|
||||
import cn.fateverse.log.entity.OperationLog;
|
||||
import cn.fateverse.log.query.OperationLogQuery;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Clay
|
||||
* @date 2022/11/1
|
||||
*/
|
||||
public interface OperationMapper {
|
||||
|
||||
/**
|
||||
* 批量保存日志信息
|
||||
*
|
||||
* @param operationLogList 日志保存信息
|
||||
*/
|
||||
int batchSave(List<OperationLog> operationLogList);
|
||||
|
||||
/**
|
||||
* 获取操作日志详情
|
||||
*
|
||||
* @param operId 操作日志id
|
||||
* @return 操作日志返回对象
|
||||
*/
|
||||
OperationLog selectById(@Param("operId") Long operId);
|
||||
|
||||
/**
|
||||
* 查询操作日志
|
||||
*
|
||||
* @param operationLogQuery
|
||||
* @return
|
||||
*/
|
||||
List<OperationLog> search(@Param("operation") OperationLogQuery operationLogQuery);
|
||||
|
||||
List<OperationLog> searchSubQuery(@Param("operation") OperationLogQuery operationLogQuery, @Param("start") Integer start, @Param("size") Integer size);
|
||||
|
||||
Long searchCount(@Param("operation") OperationLogQuery operationLogQuery, @Param("start") Integer start, @Param("size") Integer size);
|
||||
|
||||
/**
|
||||
* 删除日志
|
||||
*
|
||||
* @param operIds 操作日志id
|
||||
*/
|
||||
int delete(Long[] operIds);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package cn.fateverse.log.mq;
|
||||
|
||||
import cn.fateverse.log.service.OperationService;
|
||||
import cn.fateverse.log.entity.OperationLog;
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import com.rabbitmq.client.Channel;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.amqp.rabbit.annotation.RabbitListener;
|
||||
import org.springframework.amqp.support.AmqpHeaders;
|
||||
import org.springframework.messaging.handler.annotation.Header;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.LinkedBlockingDeque;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author Clay
|
||||
* @date 2023-08-02
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class RabbiListener {
|
||||
|
||||
|
||||
private final ThreadPoolExecutor executor;
|
||||
|
||||
private final OperationService operationService;
|
||||
/**
|
||||
* 最大重试次数
|
||||
*/
|
||||
private static final int MAX_RETRIES = 3;
|
||||
|
||||
public RabbiListener(OperationService operationService) {
|
||||
this.operationService = operationService;
|
||||
executor = new ThreadPoolExecutor(2,
|
||||
4,
|
||||
60,
|
||||
TimeUnit.SECONDS,new LinkedBlockingDeque<>(128),
|
||||
new ThreadFactoryBuilder().setNameFormat("rabbit_%d").build(),
|
||||
new ThreadPoolExecutor.CallerRunsPolicy());
|
||||
}
|
||||
|
||||
|
||||
@RabbitListener(queues = "#{queueLog.name}")
|
||||
public void consumeLog(List<OperationLog> operationLogList, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long tag) {
|
||||
executor.submit(() -> saveLog(operationLogList, channel, tag));
|
||||
}
|
||||
|
||||
|
||||
public void saveLog(List<OperationLog> operationLogList, Channel channel, long tag) {
|
||||
int retryCount = 0;
|
||||
boolean consumeStart = false;
|
||||
while (retryCount < MAX_RETRIES) {
|
||||
retryCount++;
|
||||
log.info("消费业务!");
|
||||
try {
|
||||
operationService.batchSave(operationLogList);
|
||||
consumeStart = true;
|
||||
break;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
retryCount++;
|
||||
log.error("操作日志失败,次数:" + retryCount);
|
||||
log.error("异常信息", e);
|
||||
}
|
||||
}
|
||||
try {
|
||||
if (consumeStart) {
|
||||
channel.basicAck(tag, false);
|
||||
} else {
|
||||
channel.basicNack(tag, false, false);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
package cn.fateverse.log.mq;
|
||||
|
||||
import cn.fateverse.log.configuration.RabbitProperties;
|
||||
import org.springframework.amqp.core.Binding;
|
||||
import org.springframework.amqp.core.BindingBuilder;
|
||||
import org.springframework.amqp.core.Queue;
|
||||
import org.springframework.amqp.core.TopicExchange;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Clay
|
||||
* @date 2023-08-02
|
||||
*/
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(RabbitProperties.class)
|
||||
public class RabbitConfig {
|
||||
|
||||
@Resource
|
||||
private RabbitProperties properties;
|
||||
|
||||
/**
|
||||
* 交换机
|
||||
*
|
||||
* @return topic交换机
|
||||
*/
|
||||
@Bean
|
||||
public TopicExchange exchangeLog() {
|
||||
return new TopicExchange(properties.getExchangeLog());
|
||||
}
|
||||
|
||||
/**
|
||||
* 队列
|
||||
*
|
||||
* @return 队列
|
||||
*/
|
||||
@Bean
|
||||
public Queue queueLog() {
|
||||
Map<String, Object> args = new HashMap<>(8);
|
||||
args.put("x-expires", 60000);
|
||||
return new Queue(properties.getQueueLog(), true, false, false, args);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 当前节点绑定的mq
|
||||
*
|
||||
* @param queueLog 队列
|
||||
* @param exchangeLog 交换机
|
||||
* @return 绑定结果
|
||||
*/
|
||||
@Bean
|
||||
public Binding binding(Queue queueLog, TopicExchange exchangeLog) {
|
||||
return BindingBuilder.bind(queueLog).to(exchangeLog).with(properties.getRoutingKey());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package cn.fateverse.log.service;
|
||||
|
||||
import cn.fateverse.common.core.result.page.TableDataInfo;
|
||||
import cn.fateverse.log.entity.LoginInfo;
|
||||
import cn.fateverse.log.query.LoginLogQuery;
|
||||
import cn.fateverse.log.vo.LoginInfoVo;
|
||||
|
||||
/**
|
||||
* @author Clay
|
||||
* @date 2022/11/2
|
||||
*/
|
||||
public interface LoginInfoService {
|
||||
/**
|
||||
* 保存登录日志信息
|
||||
*
|
||||
* @param info
|
||||
* @return
|
||||
*/
|
||||
int save(LoginInfo info);
|
||||
|
||||
/**
|
||||
* 登录日志查询
|
||||
*
|
||||
* @param loginLogQuery 日志查询条件
|
||||
* @return 表格数据
|
||||
*/
|
||||
TableDataInfo<LoginInfoVo> search(LoginLogQuery loginLogQuery);
|
||||
|
||||
/**
|
||||
* 删除登录日志
|
||||
*
|
||||
* @param infoIds 日志id
|
||||
*/
|
||||
void delete(Long[] infoIds);
|
||||
|
||||
/**
|
||||
* 查询登录日志详情
|
||||
*
|
||||
* @param infoId 日志id
|
||||
* @return 日志详情
|
||||
*/
|
||||
LoginInfoVo select(Long infoId);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package cn.fateverse.log.service;
|
||||
|
||||
import cn.fateverse.common.core.result.page.TableDataInfo;
|
||||
import cn.fateverse.log.entity.OperationLog;
|
||||
import cn.fateverse.log.query.OperationLogQuery;
|
||||
import cn.fateverse.log.vo.OperationLogVo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 操作日志service服务
|
||||
*
|
||||
* @author Clay
|
||||
* @date 2022/11/1
|
||||
*/
|
||||
public interface OperationService {
|
||||
|
||||
/**
|
||||
* 批量保存日志信息
|
||||
*
|
||||
* @param operationLogList 需要保存的日志信息
|
||||
*/
|
||||
void batchSave(List<OperationLog> operationLogList);
|
||||
|
||||
/**
|
||||
* 获取操作日志详情
|
||||
*
|
||||
* @param operId 操作日志id
|
||||
* @return 操作日志返回对象
|
||||
*/
|
||||
OperationLogVo select(Long operId);
|
||||
|
||||
/**
|
||||
* 获取操作日志
|
||||
*
|
||||
* @param operationLogQuery 操作日志查询
|
||||
* @return 操作日志列表
|
||||
*/
|
||||
TableDataInfo<OperationLogVo> search(OperationLogQuery operationLogQuery);
|
||||
|
||||
/**
|
||||
* 删除日志
|
||||
*
|
||||
* @param operIds 操作日志id
|
||||
*/
|
||||
void delete(Long[] operIds);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package cn.fateverse.log.service.impl;
|
||||
|
||||
import cn.fateverse.log.entity.LoginInfo;
|
||||
import cn.fateverse.log.mapper.LoginInfoMapper;
|
||||
import cn.fateverse.log.query.LoginLogQuery;
|
||||
import cn.fateverse.log.service.LoginInfoService;
|
||||
import cn.fateverse.log.utils.IpLocation;
|
||||
import cn.fateverse.log.vo.LoginInfoVo;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.fateverse.common.core.result.page.TableDataInfo;
|
||||
import cn.fateverse.common.mybatis.utils.PageUtils;
|
||||
import cn.fateverse.common.security.entity.LoginUser;
|
||||
import cn.fateverse.common.security.service.TokenService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Clay
|
||||
* @date 2022/11/2
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class LoginInfoServiceImpl implements LoginInfoService {
|
||||
|
||||
private final LoginInfoMapper loginInfoMapper;
|
||||
|
||||
private final TokenService tokenService;
|
||||
|
||||
public LoginInfoServiceImpl(LoginInfoMapper loginInfoMapper,
|
||||
TokenService tokenService) {
|
||||
this.loginInfoMapper = loginInfoMapper;
|
||||
this.tokenService = tokenService;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int save(LoginInfo info) {
|
||||
String ipddr = info.getIpddr();
|
||||
if (!StrUtil.isEmpty(ipddr)) {
|
||||
info.setLoginLocation(IpLocation.getRegion(ipddr.split(",")[0]));
|
||||
}
|
||||
if (!StrUtil.isEmpty(info.getUuid())) {
|
||||
LoginUser loginUser = tokenService.getLoginUserUUid(info.getUuid());
|
||||
if (StrUtil.isEmpty(loginUser.getLoginLocation())) {
|
||||
loginUser.setLoginLocation(info.getLoginLocation());
|
||||
tokenService.setLoginUser(loginUser);
|
||||
}
|
||||
}
|
||||
return loginInfoMapper.save(info);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableDataInfo<LoginInfoVo> search(LoginLogQuery loginLogQuery) {
|
||||
PageUtils.startPage();
|
||||
List<LoginInfo> loginInfos = loginInfoMapper.search(loginLogQuery);
|
||||
return PageUtils.convertDataTable(loginInfos, LoginInfoVo::toLoginInfoVo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(Long[] infoIds) {
|
||||
loginInfoMapper.delete(infoIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoginInfoVo select(Long infoId) {
|
||||
LoginInfo loginInfo = loginInfoMapper.selectById(infoId);
|
||||
return LoginInfoVo.toLoginInfoVo(loginInfo);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package cn.fateverse.log.service.impl;
|
||||
|
||||
import cn.fateverse.common.security.utils.SecurityUtils;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.fateverse.common.core.result.page.TableDataInfo;
|
||||
import cn.fateverse.common.mybatis.utils.PageUtils;
|
||||
import cn.fateverse.log.entity.OperationLog;
|
||||
import cn.fateverse.log.mapper.OperationMapper;
|
||||
import cn.fateverse.log.query.OperationLogQuery;
|
||||
import cn.fateverse.log.service.OperationService;
|
||||
import cn.fateverse.log.utils.IpLocation;
|
||||
import cn.fateverse.log.vo.OperationLogVo;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Clay
|
||||
* @date 2022/11/1
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class OperationServiceImpl implements OperationService {
|
||||
|
||||
private final OperationMapper operationMapper;
|
||||
|
||||
public OperationServiceImpl(OperationMapper operationMapper) {
|
||||
this.operationMapper = operationMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
|
||||
public void batchSave(List<OperationLog> operationLogList) {
|
||||
if (null == operationLogList || operationLogList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
operationLogList.forEach(operationLog -> {
|
||||
if (!StrUtil.isEmpty(operationLog.getOperIp())) {
|
||||
operationLog.setOperLocation(IpLocation.getRegion(operationLog.getOperIp().split(",")[0]));
|
||||
}
|
||||
});
|
||||
operationMapper.batchSave(operationLogList);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public OperationLogVo select(Long operId) {
|
||||
OperationLog operationLog = operationMapper.selectById(operId);
|
||||
OperationLogVo operationLogVo = OperationLogVo.toOperationLogVo(operationLog);
|
||||
if (SecurityUtils.isAdmin()) {
|
||||
operationLogVo.setErrorStackTrace(operationLog.getErrorStackTrace());
|
||||
}
|
||||
return operationLogVo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableDataInfo<OperationLogVo> search(OperationLogQuery operationLogQuery) {
|
||||
PageUtils.startPage();
|
||||
List<OperationLog> operationLogs = operationMapper.search(operationLogQuery);
|
||||
return PageUtils.convertDataTable(operationLogs, OperationLogVo::toOperationLogVo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(Long[] operIds) {
|
||||
operationMapper.delete(operIds);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package cn.fateverse.log.utils;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.lionsoul.ip2region.xdb.Searcher;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author Clay
|
||||
* @date 2023-06-02
|
||||
*/
|
||||
public class IpLocation {
|
||||
|
||||
|
||||
private static volatile Searcher searcher = null;
|
||||
|
||||
|
||||
private static Searcher getDbSearcher() {
|
||||
if (null == searcher) {
|
||||
synchronized (IpLocation.class) {
|
||||
if (null == searcher) {
|
||||
InputStream inputStream = IpLocation.class.getResourceAsStream("/ip2region.xdb");
|
||||
try {
|
||||
searcher = Searcher.newWithBuffer(IOUtils.toByteArray(inputStream));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return searcher;
|
||||
}
|
||||
|
||||
public static String getRegion(String ip) {
|
||||
String region;
|
||||
try {
|
||||
Searcher searcher = getDbSearcher();
|
||||
if (null == searcher) {
|
||||
return "";
|
||||
}
|
||||
region = searcher.search(ip);
|
||||
region = region.replaceAll("0\\|", "");
|
||||
region = Arrays.stream(region.split("\\|")).distinct().collect(Collectors.joining(" "));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return "";
|
||||
}
|
||||
return region;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
13
log/log-biz/src/main/resources/bootstrap-dev.yml
Normal file
13
log/log-biz/src/main/resources/bootstrap-dev.yml
Normal file
@@ -0,0 +1,13 @@
|
||||
# Spring
|
||||
spring:
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
# 服务注册地址
|
||||
server-addr: 10.7.127.189:38848
|
||||
namespace: clay
|
||||
|
||||
dubbo:
|
||||
registry:
|
||||
parameters:
|
||||
namespace: dubbo-clay
|
||||
11
log/log-biz/src/main/resources/bootstrap-pro.yml
Normal file
11
log/log-biz/src/main/resources/bootstrap-pro.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
# Spring
|
||||
spring:
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
# 服务注册地址
|
||||
server-addr: nacos.fateverse.svc.cluster.local:8848
|
||||
|
||||
management:
|
||||
server:
|
||||
port: 9595
|
||||
42
log/log-biz/src/main/resources/bootstrap.yml
Normal file
42
log/log-biz/src/main/resources/bootstrap.yml
Normal file
@@ -0,0 +1,42 @@
|
||||
# Tomcat
|
||||
server:
|
||||
port: 10005
|
||||
|
||||
# Spring
|
||||
spring:
|
||||
application:
|
||||
# 应用名称
|
||||
name: log
|
||||
profiles:
|
||||
# 环境配置
|
||||
active: dev
|
||||
main:
|
||||
allow-bean-definition-overriding: true
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
# 服务注册地址
|
||||
server-addr: 192.168.101.108:8848
|
||||
username: nacos
|
||||
password: nacos
|
||||
namespace: ${spring.profiles.active}
|
||||
config:
|
||||
# 配置中心地址
|
||||
server-addr: ${spring.cloud.nacos.discovery.server-addr}
|
||||
file-extension: yaml
|
||||
namespace: ${spring.profiles.active}
|
||||
shared-configs:
|
||||
- data-id: application-${spring.profiles.active}.yaml
|
||||
refresh: true
|
||||
dubbo:
|
||||
application:
|
||||
name: dubbo-${spring.application.name}
|
||||
protocol:
|
||||
name: dubbo
|
||||
port: -1
|
||||
registry:
|
||||
address: nacos://${spring.cloud.nacos.discovery.server-addr}
|
||||
username: ${spring.cloud.nacos.discovery.username}
|
||||
password: ${spring.cloud.nacos.discovery.password}
|
||||
parameters:
|
||||
namespace: dubbo-${spring.profiles.active}
|
||||
BIN
log/log-biz/src/main/resources/ip2region.xdb
Normal file
BIN
log/log-biz/src/main/resources/ip2region.xdb
Normal file
Binary file not shown.
58
log/log-biz/src/main/resources/mapper/LoginInfoMapper.xml
Normal file
58
log/log-biz/src/main/resources/mapper/LoginInfoMapper.xml
Normal file
@@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="cn.fateverse.log.mapper.LoginInfoMapper">
|
||||
<resultMap type="cn.fateverse.log.entity.LoginInfo" id="LoginInfoResult">
|
||||
<id property="infoId" column="info_id"/>
|
||||
<result property="userName" column="user_name"/>
|
||||
<result property="ipddr" column="ipaddr"/>
|
||||
<result property="loginLocation" column="login_location"/>
|
||||
<result property="browser" column="browser"/>
|
||||
<result property="os" column="os"/>
|
||||
<result property="state" column="state"/>
|
||||
<result property="msg" column="msg"/>
|
||||
<result property="loginTime" column="login_time"/>
|
||||
</resultMap>
|
||||
|
||||
<insert id="save" parameterType="cn.fateverse.log.entity.LoginInfo">
|
||||
insert into sys_login_infor
|
||||
(info_id, user_name, ipaddr, login_location, browser, os, state, msg, login_time)
|
||||
values
|
||||
(#{infoId}, #{userName}, #{ipddr}, #{loginLocation}, #{browser}, #{os}, #{state}, #{msg}, #{loginTime})
|
||||
</insert>
|
||||
<select id="search" resultMap="LoginInfoResult"
|
||||
parameterType="cn.fateverse.log.query.LoginLogQuery">
|
||||
select info_id, user_name, ipaddr, login_location, browser, os, state, msg, login_time
|
||||
from sys_login_infor
|
||||
<where>
|
||||
<if test="ipAddr !=null and ipAddr !=''">
|
||||
and ipaddr like concat('%',#{ipAddr},'%')
|
||||
</if>
|
||||
<if test="userName !=null and userName !=''">
|
||||
and user_name like concat('%',#{userName},'%')
|
||||
</if>
|
||||
<if test="state !=null and state !=''">
|
||||
and state = #{state}
|
||||
</if>
|
||||
<if test="startTime !=null">
|
||||
and login_time between #{startTime} and #{endTime}
|
||||
</if>
|
||||
</where>
|
||||
order by login_time desc
|
||||
</select>
|
||||
|
||||
<delete id="delete" parameterType="String">
|
||||
delete from sys_login_infor where info_id in
|
||||
<foreach collection="array" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</delete>
|
||||
|
||||
<select id="selectById" resultMap="LoginInfoResult">
|
||||
select info_id, user_name, ipaddr, login_location, browser, os, state, msg, login_time
|
||||
from sys_login_infor
|
||||
where info_id =#{infoId}
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
176
log/log-biz/src/main/resources/mapper/OperationMapper.xml
Normal file
176
log/log-biz/src/main/resources/mapper/OperationMapper.xml
Normal file
@@ -0,0 +1,176 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="cn.fateverse.log.mapper.OperationMapper">
|
||||
|
||||
<resultMap type="cn.fateverse.log.entity.OperationLog" id="OperationLogResult">
|
||||
<id property="operId" column="oper_id"/>
|
||||
<result property="title" column="title"/>
|
||||
<result property="businessType" column="business_type"/>
|
||||
<result property="method" column="method"/>
|
||||
<result property="requestMethod" column="request_method"/>
|
||||
<result property="operatorType" column="operator_type"/>
|
||||
<result property="operName" column="oper_name"/>
|
||||
<result property="deptName" column="dept_name"/>
|
||||
<result property="operUrl" column="oper_url"/>
|
||||
<result property="operIp" column="oper_ip"/>
|
||||
<result property="operLocation" column="oper_location"/>
|
||||
<result property="operParam" column="oper_param"/>
|
||||
<result property="jsonResult" column="json_result"/>
|
||||
<result property="state" column="state"/>
|
||||
<result property="errorMsg" column="error_msg"/>
|
||||
<result property="operTime" column="oper_time"/>
|
||||
<result property="consumeTime" column="consume_time"/>
|
||||
</resultMap>
|
||||
|
||||
|
||||
<insert id="batchSave">
|
||||
insert into sys_operation_log
|
||||
(oper_id, title, business_type, method, request_method, operator_type, oper_name, dept_name, oper_url, oper_ip,
|
||||
oper_location, oper_param, json_result, state, error_msg, error_stack_trace, oper_time, consume_time)
|
||||
values
|
||||
<foreach collection="list" item="log" separator=",">
|
||||
(#{log.operId}, #{log.title}, #{log.businessType}, #{log.method}, #{log.requestMethod}, #{log.operatorType},
|
||||
#{log.operName},
|
||||
#{log.deptName}, #{log.operUrl}, #{log.operIp}, #{log.operLocation}, #{log.operParam}, #{log.jsonResult},
|
||||
#{log.state}, #{log.errorMsg},
|
||||
#{log.errorStackTrace}, #{log.operTime}, #{log.consumeTime})
|
||||
</foreach>
|
||||
</insert>
|
||||
|
||||
<select id="searchSubQuery" resultMap="OperationLogResult"
|
||||
parameterType="cn.fateverse.log.query.OperationLogQuery">
|
||||
select oper_id, title, business_type, method, request_method, operator_type, oper_name, dept_name, oper_url,
|
||||
oper_ip, oper_location, state, oper_time, consume_time
|
||||
from sys_operation_log
|
||||
<where>
|
||||
oper_id >= (select oper_id from sys_operation_log
|
||||
<where>
|
||||
<if test="operation.title !=null and operation.title !=''">
|
||||
and title like concat('%',#{operation.title},'%')
|
||||
</if>
|
||||
<if test="operation.operName !=null and operation.operName !=''">
|
||||
and oper_name like concat('%',#{operation.operName},'%')
|
||||
</if>
|
||||
<if test="operation.businessType !=null ">
|
||||
and business_type like concat('%',#{operation.businessType},'%')
|
||||
</if>
|
||||
<if test="operation.state !=null and operation.state !=''">
|
||||
and state =#{operation.state}
|
||||
</if>
|
||||
<if test="operation.startTime !=null ">
|
||||
and oper_time >=#{operation.startTime}
|
||||
</if>
|
||||
<if test="operation.endTime !=null ">
|
||||
and oper_time <=#{operation.endTime}
|
||||
</if>
|
||||
</where>
|
||||
limit #{start},1
|
||||
)
|
||||
<if test="operation.title !=null and operation.title !=''">
|
||||
and title like concat('%',#{operation.title},'%')
|
||||
</if>
|
||||
<if test="operation.operName !=null and operation.operName !=''">
|
||||
and oper_name like concat('%',#{operation.operName},'%')
|
||||
</if>
|
||||
<if test="operation.businessType !=null ">
|
||||
and business_type like concat('%',#{operation.businessType},'%')
|
||||
</if>
|
||||
<if test="operation.state !=null and operation.state !=''">
|
||||
and state =#{operation.state}
|
||||
</if>
|
||||
<if test="operation.startTime !=null ">
|
||||
and oper_time >=#{operation.startTime}
|
||||
</if>
|
||||
<if test="operation.endTime !=null ">
|
||||
and oper_time <=#{operation.endTime}
|
||||
</if>
|
||||
</where>
|
||||
order by oper_time desc limit #{size}
|
||||
</select>
|
||||
|
||||
|
||||
<select id="search" resultMap="OperationLogResult"
|
||||
parameterType="cn.fateverse.log.query.OperationLogQuery">
|
||||
select oper_id, title, business_type, method, request_method, operator_type, oper_name, dept_name, oper_url,
|
||||
oper_ip, oper_location, state, oper_time, consume_time
|
||||
from sys_operation_log
|
||||
<where>
|
||||
<if test="operation.title !=null and operation.title !=''">
|
||||
and title like concat('%',#{operation.title},'%')
|
||||
</if>
|
||||
<if test="operation.operName !=null and operation.operName !=''">
|
||||
and oper_name like concat('%',#{operation.operName},'%')
|
||||
</if>
|
||||
<if test="operation.businessType !=null ">
|
||||
and business_type like concat('%',#{operation.businessType},'%')
|
||||
</if>
|
||||
<if test="operation.state !=null and operation.state !=''">
|
||||
and state =#{operation.state}
|
||||
</if>
|
||||
<if test="operation.startTime !=null ">
|
||||
and oper_time >=#{operation.startTime}
|
||||
</if>
|
||||
<if test="operation.endTime !=null ">
|
||||
and oper_time <=#{operation.endTime}
|
||||
</if>
|
||||
</where>
|
||||
order by oper_time desc
|
||||
</select>
|
||||
|
||||
<select id="searchCount" resultType="java.lang.Long">
|
||||
select count(*) from sys_operation_log
|
||||
<where>
|
||||
<if test="operation.title !=null and operation.title !=''">
|
||||
and title like concat('%',#{operation.title},'%')
|
||||
</if>
|
||||
<if test="operation.operName !=null and operation.operName !=''">
|
||||
and oper_name like concat('%',#{operation.operName},'%')
|
||||
</if>
|
||||
<if test="operation.businessType !=null ">
|
||||
and business_type like concat('%',#{operation.businessType},'%')
|
||||
</if>
|
||||
<if test="operation.state !=null and operation.state !=''">
|
||||
and state =#{operation.state}
|
||||
</if>
|
||||
<if test="operation.startTime !=null ">
|
||||
and oper_time >=#{operation.startTime}
|
||||
</if>
|
||||
<if test="operation.endTime !=null ">
|
||||
and oper_time <=#{operation.endTime}
|
||||
</if>
|
||||
</where>
|
||||
</select>
|
||||
|
||||
<delete id="delete" parameterType="String">
|
||||
delete from sys_operation_log where oper_id in
|
||||
<foreach collection="array" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</delete>
|
||||
|
||||
<select id="selectById" resultMap="OperationLogResult">
|
||||
select oper_id,
|
||||
title,
|
||||
business_type,
|
||||
method,
|
||||
request_method,
|
||||
operator_type,
|
||||
oper_name,
|
||||
dept_name,
|
||||
oper_url,
|
||||
oper_ip,
|
||||
oper_location,
|
||||
oper_param,
|
||||
json_result,
|
||||
state,
|
||||
error_msg,
|
||||
error_stack_trace,
|
||||
oper_time,
|
||||
consume_time
|
||||
from sys_operation_log
|
||||
where oper_id = #{operId}
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
24
log/pom.xml
Normal file
24
log/pom.xml
Normal file
@@ -0,0 +1,24 @@
|
||||
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>fateverse</artifactId>
|
||||
<groupId>cn.fateverse</groupId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>log</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<modules>
|
||||
<module>log-api</module>
|
||||
<module>log-biz</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
Reference in New Issue
Block a user