20260821230656
This commit is contained in:
1 parent
2e5d532f23
commit
c43b4c8364
144 files changed
+7665
-242
No files matched your search
@@ -10,13 +10,12 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 登录日志服务:在登录成功或失败时采集客户端信息,并通过通用 saveobjt 机制写入 s_login_log 表。
|
||||
* 登录日志服务:在登录成功或失败时采集客户端信息,并通过通用 saveobjt 机制写入 s_log_login 表。
|
||||
* 写日志失败不影响登录主流程;机构上下文通过 OrgContext 临时设置并在 finally 中清理。
|
||||
*/
|
||||
@Service
|
||||
@@ -24,6 +23,9 @@ public class LoginLogService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(LoginLogService.class);
|
||||
|
||||
/** 登录类型:密码登录(与 s_log_login.b_login_type 约定一致) */
|
||||
private static final String LOGIN_TYPE_PASSWORD = "password";
|
||||
|
||||
private final DataSaveService dataSaveService;
|
||||
private final ClientInfoExtractor clientInfoExtractor;
|
||||
|
||||
@@ -49,10 +51,10 @@ public class LoginLogService {
|
||||
|
||||
Map<String, Object> row = new LinkedHashMap<>();
|
||||
row.put("b_id", IdGenerator.nextId());
|
||||
row.put("b_org_id", orgId);
|
||||
row.put("b_user_id", userId);
|
||||
row.put("b_account", account);
|
||||
row.put("b_login_time", Timestamp.valueOf(LocalDateTime.now()));
|
||||
row.put("b_login_type", LOGIN_TYPE_PASSWORD);
|
||||
row.put("b_occurdatetime", Timestamp.from(java.time.Instant.now()));
|
||||
row.put("b_ip", info.ip());
|
||||
row.put("b_ip_location", info.ipLocation());
|
||||
row.put("b_browser", info.browser());
|
||||
@@ -66,7 +68,7 @@ public class LoginLogService {
|
||||
row.put("b_session_id", sessionId);
|
||||
|
||||
Map<String, Object> tableOp = new LinkedHashMap<>();
|
||||
tableOp.put("table", "s_login_log");
|
||||
tableOp.put("table", "s_log_login");
|
||||
tableOp.put("key_field", "b_id");
|
||||
tableOp.put("inserts", List.of(row));
|
||||
|
||||
|
||||
@@ -166,33 +166,12 @@ public class DbUtils {
|
||||
String account
|
||||
) throws SQLException {
|
||||
try (Connection connection = dataSourceManager.getConnection(orgId)) {
|
||||
SQLException failure = null;
|
||||
boolean privileged = false;
|
||||
try {
|
||||
setSystemUserVisibility(connection, 1);
|
||||
privileged = true;
|
||||
String sql = "SELECT [b_id], [b_account], [b_name], [b_password] "
|
||||
+ "FROM [b_user] WHERE [b_account] = ? AND [b_canuse] = 1";
|
||||
try (PreparedStatement statement = connection.prepareStatement(sql)) {
|
||||
statement.setString(1, account);
|
||||
try (ResultSet resultSet = statement.executeQuery()) {
|
||||
return readRows(resultSet);
|
||||
}
|
||||
}
|
||||
} catch (SQLException exception) {
|
||||
failure = exception;
|
||||
throw exception;
|
||||
} finally {
|
||||
if (privileged) {
|
||||
try {
|
||||
setSystemUserVisibility(connection, null);
|
||||
} catch (SQLException clearException) {
|
||||
if (failure != null) {
|
||||
failure.addSuppressed(clearException);
|
||||
} else {
|
||||
throw clearException;
|
||||
}
|
||||
}
|
||||
String sql = "SELECT [b_id], [b_account], [b_name], [b_password] "
|
||||
+ "FROM [b_user] WHERE [b_account] = ? AND [b_canuse] = 1";
|
||||
try (PreparedStatement statement = connection.prepareStatement(sql)) {
|
||||
statement.setString(1, account);
|
||||
try (ResultSet resultSet = statement.executeQuery()) {
|
||||
return readRows(resultSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -506,22 +485,6 @@ public class DbUtils {
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
private void setSystemUserVisibility(
|
||||
Connection connection,
|
||||
Integer value
|
||||
) throws SQLException {
|
||||
String sql = "EXEC sys.sp_set_session_context @key = ?, @value = ?";
|
||||
try (PreparedStatement statement = connection.prepareStatement(sql)) {
|
||||
statement.setString(1, "allow_g3soft");
|
||||
if (value == null) {
|
||||
statement.setNull(2, java.sql.Types.INTEGER);
|
||||
} else {
|
||||
statement.setInt(2, value);
|
||||
}
|
||||
statement.execute();
|
||||
}
|
||||
}
|
||||
|
||||
private String buildColumns(List<String> searchColumns) {
|
||||
if (searchColumns == null || searchColumns.isEmpty()) {
|
||||
return "*";
|
||||
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
package cn.g3soft.fmsapi.utils.snowflake;
|
||||
|
||||
import cn.g3soft.fmsapi.utils.snowflake.contract.IdGeneratorException;
|
||||
import cn.g3soft.fmsapi.utils.snowflake.contract.IdGeneratorOptions;
|
||||
import cn.g3soft.fmsapi.utils.snowflake.idgen.DefaultIdGenerator;
|
||||
import cn.g3soft.fmsapi.utils.snowflake.idgen.IdGenerator;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
class DefaultIdGeneratorTests {
|
||||
|
||||
private static IdGeneratorOptions options(short workerId) {
|
||||
IdGeneratorOptions o = new IdGeneratorOptions(workerId);
|
||||
o.Method = 1; // 漂移算法(生产默认,自带时钟回拨保护)
|
||||
return o;
|
||||
}
|
||||
|
||||
@Test
|
||||
void generatedIds_areUniqueInBulk() throws Exception {
|
||||
DefaultIdGenerator gen = new DefaultIdGenerator(options((short) 1));
|
||||
|
||||
int n = 100_000;
|
||||
Set<Long> ids = ConcurrentHashMap.newKeySet(n);
|
||||
for (int i = 0; i < n; i++) {
|
||||
ids.add(gen.newLong());
|
||||
}
|
||||
|
||||
assertThat(ids).hasSize(n);
|
||||
}
|
||||
|
||||
@Test
|
||||
void generatedIds_areStrictlyIncreasingInSingleThread() throws Exception {
|
||||
DefaultIdGenerator gen = new DefaultIdGenerator(options((short) 1));
|
||||
|
||||
long prev = gen.newLong();
|
||||
for (int i = 0; i < 10_000; i++) {
|
||||
long cur = gen.newLong();
|
||||
assertThat(cur).isGreaterThan(prev);
|
||||
prev = cur;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void generatedIds_concurrentNoDuplicates() throws Exception {
|
||||
DefaultIdGenerator gen = new DefaultIdGenerator(options((short) 1));
|
||||
|
||||
int threads = 8;
|
||||
int perThread = 10_000;
|
||||
Set<Long> ids = ConcurrentHashMap.newKeySet();
|
||||
ExecutorService pool = Executors.newFixedThreadPool(threads);
|
||||
CountDownLatch start = new CountDownLatch(1);
|
||||
CountDownLatch done = new CountDownLatch(threads);
|
||||
for (int t = 0; t < threads; t++) {
|
||||
pool.submit(() -> {
|
||||
try {
|
||||
start.await();
|
||||
for (int i = 0; i < perThread; i++) {
|
||||
ids.add(gen.newLong());
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
} finally {
|
||||
done.countDown();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
start.countDown();
|
||||
assertThat(done.await(30, TimeUnit.SECONDS)).isTrue();
|
||||
pool.shutdownNow();
|
||||
|
||||
assertThat(ids).hasSize(threads * perThread);
|
||||
}
|
||||
|
||||
@Test
|
||||
void generatedId_encodesWorkerIdAndApproximateTimestamp() throws Exception {
|
||||
IdGeneratorOptions o = options((short) 7);
|
||||
DefaultIdGenerator gen = new DefaultIdGenerator(o);
|
||||
|
||||
long id = gen.newLong();
|
||||
|
||||
int timestampShift = o.WorkerIdBitLength + o.SeqBitLength; // 12
|
||||
long timestamp = id >>> timestampShift;
|
||||
long workerId = (id >>> o.SeqBitLength) & ((1L << o.WorkerIdBitLength) - 1);
|
||||
|
||||
assertThat(workerId).isEqualTo(7L);
|
||||
long expectedTimestamp = System.currentTimeMillis() - o.BaseTime;
|
||||
assertThat(timestamp).isBetween(expectedTimestamp - 5_000, expectedTimestamp + 5_000);
|
||||
}
|
||||
|
||||
@Test
|
||||
void invalidOptions_areRejected() {
|
||||
IdGeneratorOptions badWorkerId = options((short) -1);
|
||||
assertThatThrownBy(() -> new DefaultIdGenerator(badWorkerId))
|
||||
.isInstanceOf(IdGeneratorException.class);
|
||||
|
||||
IdGeneratorOptions badBaseTime = options((short) 1);
|
||||
badBaseTime.BaseTime = 1000L; // 早于校验下限 315504000000
|
||||
assertThatThrownBy(() -> new DefaultIdGenerator(badBaseTime))
|
||||
.isInstanceOf(IdGeneratorException.class);
|
||||
|
||||
IdGeneratorOptions tooManyBits = options((short) 1);
|
||||
tooManyBits.WorkerIdBitLength = 22; // 22 + 6 > 22
|
||||
assertThatThrownBy(() -> new DefaultIdGenerator(tooManyBits))
|
||||
.isInstanceOf(IdGeneratorException.class);
|
||||
|
||||
IdGeneratorOptions tooSmallSeq = options((short) 1);
|
||||
tooSmallSeq.SeqBitLength = 1; // 下限 2
|
||||
assertThatThrownBy(() -> new DefaultIdGenerator(tooSmallSeq))
|
||||
.isInstanceOf(IdGeneratorException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void staticSingleton_worksAfterInitializationLikeApplicationStartup() throws Exception {
|
||||
IdGenerator.setIdGenerator(options((short) 1));
|
||||
|
||||
long id = IdGenerator.nextId();
|
||||
|
||||
assertThat(id).isPositive();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user