增加服务端配置文件与测试文件
This commit is contained in:
parent
1a66192ee8
commit
e593b545d4
|
|
@ -0,0 +1,39 @@
|
|||
spring:
|
||||
config:
|
||||
activate:
|
||||
on-profile: dev
|
||||
jpa:
|
||||
# database-platform: com.aisino.iles.core.hibernate.MysqlDialectPlus
|
||||
# database-platform: org.hibernate.dialect.Kingbase8Dialect
|
||||
database-platform: com.aisino.iles.core.hibernate.PostgreSQLDialectPlus
|
||||
hibernate:
|
||||
ddl-auto: update
|
||||
datasource:
|
||||
hikari:
|
||||
maximum-pool-size: 10
|
||||
minimum-idle: 5
|
||||
# driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
# username: socialcollect
|
||||
# password: Socialcollect@pg2025
|
||||
# jdbc-url: jdbc:mysql://mysql-dev:33060/iles_db?useSSL=false&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8
|
||||
driver-class-name: org.postgresql.Driver
|
||||
username: socialcollect
|
||||
password: Socialcollect@pg2025
|
||||
jdbc-url: jdbc:postgresql://mysql-dev:60002/iles_db?timezone=Asia/Shanghai
|
||||
pool-name: hikari-dev-pool
|
||||
data:
|
||||
redis:
|
||||
host: localhost
|
||||
port: 6379
|
||||
database: 5
|
||||
server:
|
||||
port: 9091
|
||||
|
||||
logging:
|
||||
level:
|
||||
com.aisino.iles.core.hibernate.RedissonLocalStorage: DEBUG
|
||||
com.aisino.iles.lawenforcement.controller.AuthController: debug
|
||||
org.hibernate.SQL: debug
|
||||
org.hibernate.orm.jdbc.bind: TRACE
|
||||
org.springframework.web.client.RestTemplate: DEBUG
|
||||
org.apache.kafka.clients.NetworkClient: ERROR
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
spring:
|
||||
jpa:
|
||||
database-platform: org.hibernate.dialect.Kingbase8Dialect
|
||||
hibernate:
|
||||
ddl-auto: update
|
||||
datasource:
|
||||
hikari:
|
||||
maximum-pool-size: 10
|
||||
minimum-idle: 5
|
||||
driver-class-name: com.kingbase8.Driver
|
||||
username: iles_db
|
||||
password: Zhyj@2025
|
||||
jdbc-url: jdbc:kingbase8://db:54321/iles_db?timezone=Asia/Shanghai
|
||||
pool-name: hikari-prod-pool
|
||||
data:
|
||||
redis:
|
||||
host: redis
|
||||
port: 6379
|
||||
database: 5
|
||||
kafka:
|
||||
bootstrap-servers: 10.22.245.242:9092
|
||||
listener:
|
||||
# 手动提交模式(必须配置,与enable-auto-commit: false配合)
|
||||
ack-mode: MANUAL_IMMEDIATE # 调用ack.acknowledge()后立即提交
|
||||
producer:
|
||||
key-serializer: org.apache.kafka.common.serialization.StringSerializer
|
||||
value-serializer: org.apache.kafka.common.serialization.StringSerializer
|
||||
acks: all # 确认策略:所有副本确认后返回成功
|
||||
consumer:
|
||||
group-id: zhzf-group
|
||||
auto-offset-reset: earliest # 偏移量重置策略:从最早消息开始消费
|
||||
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
|
||||
value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
|
||||
enable-auto-commit: false # 启用自动提交偏移量
|
||||
server:
|
||||
port: 9091
|
||||
custom:
|
||||
aws:
|
||||
access-key: aisino@2021
|
||||
secret-key: aisino@2021
|
||||
bucket: iles
|
||||
endpoint: http://minio:10010
|
||||
filePath:
|
||||
# 整合支撑系统认证
|
||||
sso:
|
||||
enabled: true
|
||||
base_url: http://10.22.245.209:16165/ht
|
||||
authorize_server: ${sso.base_url}/uaa
|
||||
client_id: A-610100000000-0005
|
||||
client_secret: 949783e1735b45948658b44744b0c3c3
|
||||
redirect_uri: https://10.22.245.213:10011/zhzf/index.html
|
||||
|
||||
third-party:
|
||||
enterprise:
|
||||
# 内网环境的综合执法用户的手机号码
|
||||
yddh: 18009235209
|
||||
|
||||
logging:
|
||||
level:
|
||||
com.aisino.iles.core.hibernate.RedissonLocalStorage: DEBUG
|
||||
org.hibernate.SQL: debug
|
||||
org.hibernate.orm.jdbc.bind: TRACE
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
spring:
|
||||
jpa:
|
||||
properties:
|
||||
hibernate:
|
||||
cache:
|
||||
redisson:
|
||||
hibernate:
|
||||
default-query-results-region:
|
||||
eviction:
|
||||
max_entries: 10000
|
||||
expiration:
|
||||
max_idle_time: 18000
|
||||
time_to_live: 60000
|
||||
Constant:
|
||||
eviction:
|
||||
max_entries: 40000
|
||||
expiration:
|
||||
max_idle_time: 0
|
||||
time_to_live: 0
|
||||
User:
|
||||
expiration:
|
||||
time_to_live: 600000
|
||||
max_idle_time: 300000
|
||||
eviction:
|
||||
max_entries: 20000
|
||||
Function:
|
||||
expiration:
|
||||
time_to_live: 0
|
||||
max_idle_time: 0
|
||||
eviction:
|
||||
max_entries: 10000
|
||||
Menu:
|
||||
expiration:
|
||||
time_to_live: 0
|
||||
max_idle_time: 0
|
||||
eviction:
|
||||
max_entries: 4000
|
||||
UserType:
|
||||
expiration:
|
||||
time_to_live: 0
|
||||
max_idle_time: 0
|
||||
eviction:
|
||||
max_entries: 1000
|
||||
Permission:
|
||||
expiration:
|
||||
time_to_live: 0
|
||||
max_idle_time: 0
|
||||
eviction:
|
||||
max_entries: 5000
|
||||
Role:
|
||||
expiration:
|
||||
time_to_live: 0
|
||||
max_idle_time: 0
|
||||
eviction:
|
||||
max_entries: 4000
|
||||
Resource:
|
||||
expiration:
|
||||
time_to_live: 0
|
||||
max_idle_time: 0
|
||||
eviction:
|
||||
max_entries: 10000
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
spring:
|
||||
jpa:
|
||||
database-platform: org.hibernate.dialect.Kingbase8Dialect
|
||||
hibernate:
|
||||
ddl-auto: update
|
||||
datasource:
|
||||
hikari:
|
||||
maximum-pool-size: 10
|
||||
minimum-idle: 5
|
||||
driver-class-name: com.kingbase8.Driver
|
||||
username: iles_user
|
||||
password: iles_user@2025
|
||||
jdbc-url: jdbc:kingbase8://db:54321/iles_db?timezone=Asia/Shanghai
|
||||
pool-name: hikari-test-pool
|
||||
server:
|
||||
port: 9091
|
||||
custom:
|
||||
aws:
|
||||
access-key: aisino@2021
|
||||
secret-key: aisino@2021
|
||||
bucket: iles
|
||||
endpoint: http://10.22.245.219:10010
|
||||
filePath:
|
||||
# 整合支撑系统认证
|
||||
sso:
|
||||
enabled: true
|
||||
base_url: http://10.22.245.219:16165/ht
|
||||
authorize_server: ${sso.base_url}/uaa
|
||||
client_id: A-610100000000-0005
|
||||
client_secret: 949783e1735b45948658b44744b0c3c3
|
||||
redirect_uri: http://10.22.245.219:10011/zhzf/index.html
|
||||
|
||||
third-party:
|
||||
enterprise:
|
||||
# 内网环境的综合执法用户的手机号码
|
||||
yddh: 13996761895
|
||||
|
||||
logging:
|
||||
level:
|
||||
com.aisino.iles.core.hibernate.RedissonLocalStorage: DEBUG
|
||||
com.aisino.iles.lawenforcement.controller.AuthController: debug
|
||||
org.hibernate.SQL: debug
|
||||
org.hibernate.orm.jdbc.bind: TRACE
|
||||
org.springframework.web.client.RestTemplate: DEBUG
|
||||
|
|
@ -0,0 +1,196 @@
|
|||
spring:
|
||||
profiles:
|
||||
include:
|
||||
- redisson-cache
|
||||
jpa:
|
||||
open-in-view: false
|
||||
hibernate:
|
||||
ddl-auto: none
|
||||
properties:
|
||||
hibernate:
|
||||
default_batch_fetch_size: 50
|
||||
jdbc:
|
||||
batch_size: 50
|
||||
cache:
|
||||
use_second_level_cache: true
|
||||
use_query_cache: true
|
||||
# region.factory_class: org.redisson.hibernate.RedissonRegionFactory
|
||||
region_prefix: hibernate
|
||||
redisson:
|
||||
fallback: true
|
||||
generate.statistics: true
|
||||
cache:
|
||||
type: redis
|
||||
data:
|
||||
redis:
|
||||
host: localhost
|
||||
port: 6379
|
||||
password: null
|
||||
database: 0
|
||||
repositories:
|
||||
enabled: false
|
||||
servlet:
|
||||
multipart:
|
||||
max-file-size: 1000MB
|
||||
max-request-size: 1000MB
|
||||
jackson:
|
||||
locale: zh_CN
|
||||
time-zone: Asia/Shanghai
|
||||
serialization:
|
||||
write_dates_as_timestamps: false # 关闭序列化的时候,把时间按照毫秒方式输出的特性
|
||||
redisson:
|
||||
config: |
|
||||
singleServerConfig:
|
||||
address: "redis://${spring.data.redis.host}:${spring.data.redis.port}"
|
||||
connectionMinimumIdleSize: 10
|
||||
connectionPoolSize: 64
|
||||
idleConnectionTimeout: 10000
|
||||
connectTimeout: 10000
|
||||
timeout: 3000
|
||||
retryAttempts: 3
|
||||
retryInterval: 1500
|
||||
password: null
|
||||
subscriptionsPerConnection: 24
|
||||
clientName: "redisson-client"
|
||||
sslEnableEndpointIdentification: false
|
||||
database: ${spring.data.redis.database}
|
||||
|
||||
server:
|
||||
servlet:
|
||||
session:
|
||||
timeout: 180
|
||||
|
||||
logging:
|
||||
file:
|
||||
name: ./logs/iles.log
|
||||
logback:
|
||||
rollingpolicy:
|
||||
max-history: 7
|
||||
max-file-size: 10MB
|
||||
total-size-cap: 5GB
|
||||
charset:
|
||||
console: UTF-8
|
||||
file: UTF-8
|
||||
level:
|
||||
org.hibernate.cache: DEBUG
|
||||
com.aisino.iles: INFO
|
||||
|
||||
custom:
|
||||
aws:
|
||||
access-key: aisino@2021
|
||||
secret-key: aisino@2021
|
||||
bucket: bucket-test
|
||||
endpoint: https://mysql-dev:10010
|
||||
filePath:
|
||||
# 整合支撑系统认证
|
||||
sso:
|
||||
enabled: true
|
||||
base_url: http://218.77.106.90:16166/ht
|
||||
authorize_server: ${sso.base_url}/uaa
|
||||
client_id: A-610100000000-0005
|
||||
client_secret: 949783e1735b45948658b44744b0c3c3
|
||||
redirect_uri: http://localhost:5173/zhzf/index.html
|
||||
|
||||
#第三方接口相关配置
|
||||
third-party:
|
||||
#消息服务
|
||||
message:
|
||||
url: ${sso.base_url}/msg/v1/messages/create
|
||||
dict: ${sso.base_url}/system/dict/cache/
|
||||
enterprise:
|
||||
yddh: 18685429490
|
||||
#互联网
|
||||
query: ${sso.base_url}/jcxxgl/company/jbxx/queryPage
|
||||
save: ${sso.base_url}/jcxxgl/company/jbxx/save
|
||||
token: ${sso.base_url}/uaa/oauth/backendServiceToken
|
||||
refresh: ${sso.base_url}/uaa/oauth/token
|
||||
selfInsAndSelfReport: ${sso.base_url}/jcxxglApi/djbQyfxxj/queryPage
|
||||
produceLicensePage: ${sso.base_url}/jcxxglApi/djbQyscxk/queryPage
|
||||
hazardPage: ${sso.base_url}/jcxxglApi/djbQyyhxx/queryPage
|
||||
sourcesDangerPage: ${sso.base_url}/jcxxglApi/djbQyzdbw/queryPage
|
||||
|
||||
report_check:
|
||||
query: https://xa-pro.12350.work/backend/php/complaintsReport/index
|
||||
single: https://xa-pro.12350.work/backend/php/complaintsReport/detail
|
||||
sign: x7Dp9K2zR4bY8qW3
|
||||
# 执法机构信息
|
||||
agency:
|
||||
query: ${sso.base_url}/system/sysDept/queryPage
|
||||
# 执法人员信息
|
||||
person:
|
||||
query: ${sso.base_url}/system/sysUser/queryPage
|
||||
roles:
|
||||
# 执法市级
|
||||
- zhzfsj
|
||||
# 执法区级
|
||||
- zhzfxj
|
||||
# 执法检查
|
||||
- zhzfjc
|
||||
# 文书送达
|
||||
delivery:
|
||||
username: zhifa
|
||||
password: zhifa@95113
|
||||
base-url: http://10.22.245.226:9080/xtjy
|
||||
publish-sms-call-url: ${third-party.delivery.base-url}/kt-module-task/v1/callAndResponse/publishSMS
|
||||
publish-voice-call-url: ${third-party.delivery.base-url}/kt-module-task/v1/callAndResponse/publishVoice
|
||||
# 执法信息
|
||||
enforcement:
|
||||
save: ${sso.base_url}/djbZfajxx/save
|
||||
# 执法文书
|
||||
document:
|
||||
save: ${sso.base_url}/djbZfwsxx/save
|
||||
# 执法检查
|
||||
enforce-check:
|
||||
save: ${sso.base_url}/djbZfjcxx/save
|
||||
# 执法案件
|
||||
case:
|
||||
save: ${sso.base_url}/djbZfajxx/save
|
||||
agency-arr: 01610100000726000-01610100000701000-01610100000016000-01610100000715000-01610100000726000-01610100000037000
|
||||
|
||||
|
||||
iles:
|
||||
sync:
|
||||
api:
|
||||
base-url: ${sso.base_url}
|
||||
dto-converters:
|
||||
"com.aisino.iles.lawenforcement.model.Document": com.aisino.iles.lawenforcement.model.dto.DjbZfwsxxRequestDto
|
||||
"com.aisino.iles.lawenforcement.model.EnforcementInfo": com.aisino.iles.lawenforcement.model.dto.DjbZfjbxxRequestDto
|
||||
"com.aisino.iles.lawenforcement.model.EnforceCheck": com.aisino.iles.lawenforcement.model.dto.DjbZfjcxxRequestDto
|
||||
"com.aisino.iles.lawenforcement.model.Case": com.aisino.iles.lawenforcement.model.dto.DjbZfajxxRequestDto
|
||||
endpoints:
|
||||
com.aisino.iles.lawenforcement.model.dto.DjbZfajxxRequestDto: /djbZfajxx/save
|
||||
com.aisino.iles.lawenforcement.model.dto.DjbZfwsxxRequestDto: /djbZfwsxx/save
|
||||
com.aisino.iles.lawenforcement.model.dto.DjbZfjcxxRequestDto: /djbZfjcxx/save
|
||||
com.aisino.iles.lawenforcement.model.dto.DjbZfjbxxRequestDto: /djbZfjbxx/save
|
||||
|
||||
scheduler:
|
||||
enabled: false
|
||||
task:
|
||||
enterprise:
|
||||
cron.expression: 20 16 * * * ?
|
||||
agency:
|
||||
cron.expression: 0 0 1 * * ?
|
||||
officer:
|
||||
cron.expression: 0 0 1 * * ?
|
||||
waferEnterprise:
|
||||
cron.expression: 0 2 * * * ?
|
||||
|
||||
data-package:
|
||||
#是否打开JPA事务拦截器 默认true
|
||||
enable: true
|
||||
# 打包标记
|
||||
packaging-flag: false
|
||||
# 打包接口
|
||||
packaging-api: http://localhost:8090/dtt/pack
|
||||
# 写入目标redis失败时,重试次数
|
||||
retry-times: 3
|
||||
# 写入目标redis失败时,重试间隔时间(毫秒)
|
||||
retry-interval: 200
|
||||
# 数据包后续业务处理器
|
||||
data-pack-processors:
|
||||
- sendToDttPack
|
||||
# 需要打包的实体名称(列表)
|
||||
process-entity-names:
|
||||
include:
|
||||
- com.aisino.iles.core.model.*
|
||||
- com.aisino.iles.lawenforcement.model.*
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,24 @@
|
|||
# 服务地址 格式 ip:port
|
||||
address: 10.22.245.159:19190
|
||||
## 以下两项使用kcsp平台的kms必填,均由kcsp平台提供。非kcsp平台可为空
|
||||
contextPath:
|
||||
kid:
|
||||
#以下两项必填(由kms aksk 管理解密生成)
|
||||
accessKey: Sgk5hVoeEEpgUhK7
|
||||
secretKey: eWjPzctSUTODF2Xm
|
||||
#使用cbc模式加密的keyId,可为空
|
||||
cbcKeyId:
|
||||
#使用ctr模式加密的keyId,可为空
|
||||
crtKeyId:
|
||||
#是否使用tls
|
||||
useTLS: false
|
||||
#本地信任keyStore路径
|
||||
trustStorePath:
|
||||
#本地信任keyStore密码
|
||||
trustStorePassword:
|
||||
#本地keyStore路径
|
||||
keyStorePath:
|
||||
#本地keyStore密码
|
||||
keyStorePassword:
|
||||
#本地keyStore中key的密码
|
||||
keyPassword:
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
|
||||
<!-- Spring Boot的基本配置 -->
|
||||
<include resource="org/springframework/boot/logging/logback/base.xml"/>
|
||||
|
||||
<!-- Dead-Letter日志Appender -->
|
||||
<appender name="DEAD_LETTER_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>logs/dead-letter.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- 每天滚动 -->
|
||||
<fileNamePattern>logs/dead-letter.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<!-- 保留30天的日志 -->
|
||||
<maxHistory>30</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<!-- 只日志信息,因为已经是JSON格式 -->
|
||||
<pattern>%msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- Dead-Letter Queue日志 -->
|
||||
<!-- 写入DEAD_LETTER_FILE Appender -->
|
||||
<!-- additivity="false" 使日志不再传递到root logger,避免日志重复 -->
|
||||
<logger name="dead-letter-log" level="ERROR" additivity="false">
|
||||
<appender-ref ref="DEAD_LETTER_FILE" />
|
||||
</logger>
|
||||
|
||||
<!-- 可以在这里添加其他日志配置 -->
|
||||
|
||||
</configuration>
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
package com.aisino.iles.core.hibernate;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.PersistenceContext;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.hibernate.Session;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* PostgreSQLDialectPlus集成测试类
|
||||
* 用于验证SQL生成是否符合预期
|
||||
*
|
||||
* @author Cascade
|
||||
* @since 2025-08-08
|
||||
*/
|
||||
@Slf4j
|
||||
@SpringBootTest
|
||||
@ActiveProfiles("test")
|
||||
@Transactional
|
||||
class PostgreSQLDialectPlusIntegrationTest {
|
||||
|
||||
@PersistenceContext
|
||||
private EntityManager entityManager;
|
||||
|
||||
@Test
|
||||
void testJsonValueFunctionSimplePathSqlGeneration() {
|
||||
// 获取Hibernate Session
|
||||
Session session = entityManager.unwrap(Session.class);
|
||||
|
||||
// 创建一个包含json_value函数的HQL查询
|
||||
String hql = "SELECT json_value('{\"name\":\"John\", \"info\":{\"age\":30}}', '$.info.age')";
|
||||
|
||||
String result = (String) session.createQuery(hql).getSingleResult();
|
||||
assertEquals("30", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testJsonValueFunctionTranslationVerification() {
|
||||
// 获取Hibernate Session
|
||||
Session session = entityManager.unwrap(Session.class);
|
||||
|
||||
// 测试不同的JSON路径模式
|
||||
String[] testCases = {
|
||||
"SELECT json_value(jsonData, '$.property')",
|
||||
"SELECT json_value(jsonData, '$.nested.object')",
|
||||
"SELECT json_value(jsonData, '$.array[0].item')"
|
||||
};
|
||||
|
||||
for (String hql : testCases) {
|
||||
try {
|
||||
// 尝试将HQL转换为SQL
|
||||
String sql = session.createQuery(hql).getQueryString();
|
||||
System.out.println("HQL: " + hql);
|
||||
System.out.println("生成的SQL: " + sql);
|
||||
|
||||
// 验证是否包含json_extract_path_text函数
|
||||
assertTrue(sql.contains("json_extract_path_text"),
|
||||
"所有json_value函数调用都应该被转译为json_extract_path_text");
|
||||
} catch (Exception e) {
|
||||
// 打印异常但不失败,因为某些复杂路径可能不被支持
|
||||
System.out.println("处理HQL时出现警告: " + hql + " - " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
package com.aisino.iles.core.service;
|
||||
|
||||
import com.aisino.iles.core.hibernate.RedissonLocalStorage;
|
||||
import com.aisino.iles.core.hibernate.RedissonRegionFactoryPlus;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class CacheAdminServicePerformanceTest {
|
||||
|
||||
private static final int THREAD_COUNT = 10;
|
||||
private static final int OPERATION_COUNT = 1000;
|
||||
private static final String TEST_REGION = "performanceTest";
|
||||
private static final String KEY_PREFIX = "key";
|
||||
private static final String VALUE_PREFIX = "value";
|
||||
|
||||
@Mock
|
||||
private RedissonRegionFactoryPlus regionFactory;
|
||||
|
||||
@Mock
|
||||
private RedissonLocalStorage region;
|
||||
|
||||
@InjectMocks
|
||||
private CacheAdminService cacheAdminService;
|
||||
|
||||
private ExecutorService executorService;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
when(regionFactory.getAllCacheRegions()).thenReturn(Map.of(TEST_REGION, region));
|
||||
executorService = Executors.newFixedThreadPool(THREAD_COUNT);
|
||||
}
|
||||
|
||||
@Test
|
||||
void concurrentPutAndGetOperations_ShouldNotLoseData() {
|
||||
// Arrange
|
||||
AtomicInteger successCount = new AtomicInteger();
|
||||
AtomicInteger failureCount = new AtomicInteger();
|
||||
|
||||
// Act - Perform concurrent put operations
|
||||
var putFutures = IntStream.range(0, OPERATION_COUNT)
|
||||
.mapToObj(i -> CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
String key = KEY_PREFIX + i;
|
||||
String value = VALUE_PREFIX + i;
|
||||
when(region.getFromCache(key, null)).thenReturn(value);
|
||||
doNothing().when(region).putIntoCache(key, value, null);
|
||||
|
||||
boolean result = cacheAdminService.putCacheValue(TEST_REGION, key, value);
|
||||
if (result) {
|
||||
successCount.incrementAndGet();
|
||||
} else {
|
||||
failureCount.incrementAndGet();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
failureCount.incrementAndGet();
|
||||
}
|
||||
}, executorService))
|
||||
.toArray(CompletableFuture[]::new);
|
||||
|
||||
// Wait for all operations to complete
|
||||
CompletableFuture.allOf(putFutures).join();
|
||||
|
||||
// Verify all puts were successful
|
||||
assertEquals(OPERATION_COUNT, successCount.get());
|
||||
assertEquals(0, failureCount.get());
|
||||
verify(region, times(OPERATION_COUNT)).putIntoCache(any(), any(), any());
|
||||
|
||||
// Reset counters for get operations
|
||||
successCount.set(0);
|
||||
failureCount.set(0);
|
||||
|
||||
// Perform concurrent get operations
|
||||
var getFutures = IntStream.range(0, OPERATION_COUNT)
|
||||
.mapToObj(i -> CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
String key = KEY_PREFIX + i;
|
||||
String expectedValue = VALUE_PREFIX + i;
|
||||
when(region.getFromCache(key, null)).thenReturn(expectedValue);
|
||||
|
||||
Object value = cacheAdminService.getCacheValue(TEST_REGION, key);
|
||||
if (expectedValue.equals(value)) {
|
||||
successCount.incrementAndGet();
|
||||
} else {
|
||||
failureCount.incrementAndGet();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
failureCount.incrementAndGet();
|
||||
}
|
||||
}, executorService))
|
||||
.toArray(CompletableFuture[]::new);
|
||||
|
||||
// Wait for all get operations to complete
|
||||
CompletableFuture.allOf(getFutures).join();
|
||||
|
||||
// Verify all gets were successful
|
||||
assertEquals(OPERATION_COUNT, successCount.get());
|
||||
assertEquals(0, failureCount.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCacheEvictionPerformance() {
|
||||
// Arrange
|
||||
int cacheSize = 1000;
|
||||
int iterations = 10000;
|
||||
|
||||
// Warm up the cache
|
||||
for (int i = 0; i < cacheSize; i++) {
|
||||
String key = KEY_PREFIX + i;
|
||||
String value = VALUE_PREFIX + i;
|
||||
cacheAdminService.putCacheValue(TEST_REGION, key, value);
|
||||
}
|
||||
|
||||
// Act - Perform cache operations under load
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
IntStream.range(0, iterations).parallel().forEach(i -> {
|
||||
String key = KEY_PREFIX + (i % cacheSize);
|
||||
if (i % 10 == 0) {
|
||||
// Every 10th operation is a put
|
||||
String newValue = VALUE_PREFIX + (i % cacheSize) + "_updated";
|
||||
cacheAdminService.putCacheValue(TEST_REGION, key, newValue);
|
||||
} else if (i % 5 == 0) {
|
||||
// Every 5th operation is a remove
|
||||
cacheAdminService.removeCacheValue(TEST_REGION, key);
|
||||
} else {
|
||||
// Other operations are gets
|
||||
cacheAdminService.getCacheValue(TEST_REGION, key);
|
||||
}
|
||||
});
|
||||
|
||||
long endTime = System.currentTimeMillis();
|
||||
long totalTime = endTime - startTime;
|
||||
|
||||
// Assert - Verify performance metrics
|
||||
double operationsPerSecond = (double) iterations / (totalTime / 1000.0);
|
||||
System.out.printf("Performance Test Results:%n");
|
||||
System.out.printf("Total operations: %d%n", iterations);
|
||||
System.out.printf("Total time: %d ms%n", totalTime);
|
||||
System.out.printf("Operations per second: %.2f%n", operationsPerSecond);
|
||||
|
||||
// Verify that the cache operations completed in a reasonable time
|
||||
assertTrue(totalTime < 5000, "Cache operations took too long: " + totalTime + "ms");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
package com.aisino.iles.core.service;
|
||||
|
||||
import com.aisino.iles.core.hibernate.RedissonLocalStorage;
|
||||
import com.aisino.iles.core.hibernate.RedissonRegionFactoryPlus;
|
||||
import jakarta.persistence.Cache;
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.EntityManagerFactory;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class CacheAdminServiceTest {
|
||||
|
||||
@Mock
|
||||
private RedissonRegionFactoryPlus regionFactory;
|
||||
|
||||
@Mock
|
||||
private EntityManager entityManager;
|
||||
|
||||
@Mock
|
||||
private EntityManagerFactory entityManagerFactory;
|
||||
|
||||
@Mock
|
||||
private Cache cache;
|
||||
|
||||
@InjectMocks
|
||||
private CacheAdminService cacheAdminService;
|
||||
|
||||
private final String testRegion = "testRegion";
|
||||
private final String testKey = "testKey";
|
||||
private final String testValue = "testValue";
|
||||
private final String entityName = "com.example.Entity";
|
||||
private final Object entityId = 1L;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
when(entityManager.getEntityManagerFactory()).thenReturn(entityManagerFactory);
|
||||
when(entityManagerFactory.getCache()).thenReturn(cache);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getAllRegions_ShouldReturnAllRegions() {
|
||||
// Arrange
|
||||
Map<String, RedissonLocalStorage> expectedRegions = new HashMap<>();
|
||||
expectedRegions.put("region1", mock(RedissonLocalStorage.class));
|
||||
expectedRegions.put("region2", mock(RedissonLocalStorage.class));
|
||||
when(regionFactory.getAllCacheRegions()).thenReturn(expectedRegions);
|
||||
|
||||
// Act
|
||||
Map<String, RedissonLocalStorage> result = cacheAdminService.getAllRegions();
|
||||
|
||||
// Assert
|
||||
assertNotNull(result);
|
||||
assertEquals(2, result.size());
|
||||
assertTrue(result.containsKey("region1"));
|
||||
assertTrue(result.containsKey("region2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getCacheValue_WhenRegionExists_ShouldReturnValue() {
|
||||
// Arrange
|
||||
RedissonLocalStorage region = mock(RedissonLocalStorage.class);
|
||||
when(regionFactory.getAllCacheRegions()).thenReturn(Map.of(testRegion, region));
|
||||
when(region.getFromCache(testKey, null)).thenReturn(testValue);
|
||||
|
||||
// Act
|
||||
Object result = cacheAdminService.getCacheValue(testRegion, testKey);
|
||||
|
||||
// Assert
|
||||
assertEquals(testValue, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getCacheValue_WhenRegionNotExists_ShouldReturnNull() {
|
||||
// Arrange
|
||||
when(regionFactory.getAllCacheRegions()).thenReturn(new HashMap<>());
|
||||
// Act
|
||||
Object result = cacheAdminService.getCacheValue("nonExistentRegion", testKey);
|
||||
// Assert
|
||||
assertNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void putCacheValue_ShouldReturnTrueWhenSuccessful() {
|
||||
// Arrange
|
||||
RedissonLocalStorage region = mock(RedissonLocalStorage.class);
|
||||
when(regionFactory.getAllCacheRegions()).thenReturn(Map.of(testRegion, region));
|
||||
doNothing().when(region).putIntoCache(testKey, testValue, null);
|
||||
|
||||
// Act
|
||||
boolean result = cacheAdminService.putCacheValue(testRegion, testKey, testValue);
|
||||
|
||||
// Assert
|
||||
assertTrue(result);
|
||||
verify(region).putIntoCache(testKey, testValue, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
void removeCacheValue_ShouldReturnTrueWhenSuccessful() {
|
||||
// Arrange
|
||||
RedissonLocalStorage region = mock(RedissonLocalStorage.class);
|
||||
when(regionFactory.getAllCacheRegions()).thenReturn(Map.of(testRegion, region));
|
||||
doNothing().when(region).removeFromCache(testKey, null);
|
||||
|
||||
// Act
|
||||
boolean result = cacheAdminService.removeCacheValue(testRegion, testKey);
|
||||
|
||||
// Assert
|
||||
assertTrue(result);
|
||||
verify(region).removeFromCache(testKey, null);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void removeCacheValueByEntityManager_ShouldEvictEntityCache() throws Exception {
|
||||
// Arrange
|
||||
Class<?> entityClass = Object.class;
|
||||
when(entityManager.getEntityManagerFactory()).thenReturn(entityManagerFactory);
|
||||
when(entityManagerFactory.getCache()).thenReturn(cache);
|
||||
|
||||
try (MockedStatic<Class> mocked = mockStatic(Class.class)) {
|
||||
mocked.when(() -> Class.forName(entityName)).thenReturn(entityClass);
|
||||
|
||||
// Act
|
||||
boolean result = cacheAdminService.removeCacheValueByEntityManager(entityName, entityId);
|
||||
|
||||
// Assert
|
||||
assertTrue(result);
|
||||
verify(cache).evict(entityClass, entityId);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void refreshLocalCache_ShouldCallGetFromCache() {
|
||||
// Arrange
|
||||
RedissonLocalStorage region = mock(RedissonLocalStorage.class);
|
||||
when(regionFactory.getAllCacheRegions()).thenReturn(Map.of(testRegion, region));
|
||||
|
||||
// Act
|
||||
cacheAdminService.refreshLocalCache(testRegion, testKey);
|
||||
// Assert
|
||||
verify(region).getFromCache(testKey, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
void removeRegion_ShouldReturnTrueWhenSuccessful() {
|
||||
// Arrange
|
||||
RedissonLocalStorage region = mock(RedissonLocalStorage.class);
|
||||
when(regionFactory.getAllCacheRegions()).thenReturn(Map.of(testRegion, region));
|
||||
doNothing().when(region).clearCache(null);
|
||||
|
||||
// Act
|
||||
boolean result = cacheAdminService.removeRegion(testRegion);
|
||||
|
||||
// Assert
|
||||
assertTrue(result);
|
||||
verify(region).clearCache(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
void removeRegion_WhenExceptionOccurs_ShouldReturnFalse() {
|
||||
// Arrange
|
||||
RedissonLocalStorage region = mock(RedissonLocalStorage.class);
|
||||
when(regionFactory.getAllCacheRegions()).thenReturn(Map.of(testRegion, region));
|
||||
doThrow(new RuntimeException("Clear cache failed")).when(region).clearCache(null);
|
||||
|
||||
// Act
|
||||
boolean result = cacheAdminService.removeRegion(testRegion);
|
||||
|
||||
// Assert
|
||||
assertFalse(result);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
package com.aisino.iles.lawenforcement.schedule.service;
|
||||
|
||||
import com.aisino.iles.lawenforcement.repository.OfficerRepository;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* OfficerScheduleService 的集成测试.
|
||||
* <p>
|
||||
* 注意: 这是一个集成测试,它会真实地调用外部API并与数据库进行交互。
|
||||
* 在运行此测试之前,请确保 application.yml 或相关 profile 中的配置
|
||||
* (如 third-party.person.*, sso.*, 数据库连接等) 是正确且可用的。
|
||||
* </p>
|
||||
*/
|
||||
@SpringBootTest(properties = {
|
||||
"third-party.enterprise.idno=310000199308124725"
|
||||
})
|
||||
@ActiveProfiles("dev")
|
||||
@DisplayName("执法人员信息同步服务集成测试")
|
||||
class OfficerScheduleServiceTest {
|
||||
|
||||
@Autowired
|
||||
private OfficerScheduleService officerScheduleService;
|
||||
|
||||
@Autowired
|
||||
private OfficerRepository officerRepository;
|
||||
|
||||
@Test
|
||||
@DisplayName("测试 scheduleTask 方法 - 完整同步流程")
|
||||
void testScheduleTask() {
|
||||
// GIVEN: 记录测试前的执法人员数量
|
||||
long countBefore = officerRepository.count();
|
||||
System.out.println("同步任务执行前,数据库中有 " + countBefore + " 名执法人员。");
|
||||
|
||||
// WHEN: 执行同步任务
|
||||
// THEN: 断言它不会抛出异常
|
||||
assertDoesNotThrow(() -> {
|
||||
officerScheduleService.scheduleTask();
|
||||
}, "执行执法人员同步任务时,不应抛出异常");
|
||||
|
||||
// AND: 记录测试后的执法人员数量
|
||||
long countAfter = officerRepository.count();
|
||||
System.out.println("同步任务执行后,数据库中有 " + countAfter + " 名执法人员。");
|
||||
|
||||
// AND: 断言任务执行后,数据量可能增加或保持不变(如果API没有新数据或数据已存在)
|
||||
assertTrue(countAfter >= countBefore, "同步后执法人员数量应大于或等于同步前");
|
||||
|
||||
System.out.println("执法人员同步任务测试成功。");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
package com.aisino.iles.lawenforcement.service;
|
||||
|
||||
import com.aisino.iles.lawenforcement.model.dto.DjbZfajxxRequestDto;
|
||||
import com.aisino.iles.lawenforcement.model.Agency;
|
||||
import com.aisino.iles.lawenforcement.model.Case;
|
||||
import com.aisino.iles.lawenforcement.model.EnforcementInfo;
|
||||
import com.aisino.iles.lawenforcement.model.Enterprise;
|
||||
import com.aisino.iles.lawenforcement.model.dto.EnforcementInfoDto;
|
||||
import com.aisino.iles.lawenforcement.model.enums.FlowNode;
|
||||
import com.aisino.iles.lawenforcement.repository.CaseRepository;
|
||||
import com.aisino.iles.lawenforcement.repository.EnforcementInfoRepository;
|
||||
import com.smartlx.sso.client.model.RemoteUserInfo;
|
||||
import lombok.SneakyThrows;
|
||||
import org.apache.commons.beanutils.BeanUtils;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* 执法信息单元测试
|
||||
*/
|
||||
@SpringBootTest
|
||||
@ActiveProfiles("dev")
|
||||
public class CaseServiceTest {
|
||||
|
||||
@Autowired
|
||||
private CaseService caseService;
|
||||
|
||||
@Autowired
|
||||
private CaseRepository caseRepository;
|
||||
|
||||
@Autowired
|
||||
private EnforcementInfoRepository enforcementInfoRepository;
|
||||
|
||||
@Autowired
|
||||
private EnforcementInfoService enforcementInfoService;
|
||||
|
||||
/**
|
||||
* 测试保存执法案件信息
|
||||
*/
|
||||
@SneakyThrows
|
||||
@Test
|
||||
@DisplayName("测试保存执法案件信息")
|
||||
@Transactional // 使用事务确保测试后数据回滚,不影响数据库
|
||||
public void testSaveLawEnforcementCase() {
|
||||
// 创建测试所需的执法机构
|
||||
Agency agency = new Agency();
|
||||
agency.setAgencyId("1");
|
||||
agency.setAgencyName("测试执法机构");
|
||||
agency.setAgencyCode("TEST_AGENCY_CODE");
|
||||
|
||||
// 创建测试所需的企业
|
||||
Enterprise enterprise = new Enterprise();
|
||||
// enterprise.setEnterpriseId(UUID.randomUUID().toString());
|
||||
enterprise.setUnitName("测试企业");
|
||||
enterprise.setUnifiedSocialCode("TEST_UNIT_CODE");
|
||||
|
||||
// 创建执法信息
|
||||
EnforcementInfo enforcementInfo = new EnforcementInfo();
|
||||
// enforcementInfo.setEnforcementId(UUID.randomUUID().toString());
|
||||
enforcementInfo.setAgency(agency);
|
||||
enforcementInfo.setAgencyId(agency.getAgencyId());
|
||||
enforcementInfo.setEnterprise(enterprise);
|
||||
enforcementInfo.setCurrentNodeCode(FlowNode.filed);
|
||||
enforcementInfo.setCreateTime(LocalDateTime.now());
|
||||
EnforcementInfoDto enforcementInfoDto = new EnforcementInfoDto();
|
||||
BeanUtils.copyProperties(enforcementInfoDto,enforcementInfo);
|
||||
enforcementInfoDto.setEnterpriseIds(List.of("01jpebdtden62z6qw01e338zwm"));
|
||||
// 保存执法信息
|
||||
List<Object> objects = enforcementInfoService.saveEnforcementInfo(enforcementInfoDto, new RemoteUserInfo());
|
||||
EnforcementInfo savedEnforcementInfo = (EnforcementInfo) objects.get(0);
|
||||
|
||||
// 创建案件信息
|
||||
Case lawCase = new Case();
|
||||
// lawCase.setCaseId(UUID.randomUUID().toString());
|
||||
lawCase.setCaseName("测试执法案件");
|
||||
lawCase.setCaseNum("TEST-CASE-" + System.currentTimeMillis());
|
||||
lawCase.setFillingDate(LocalDate.now());
|
||||
lawCase.setEnforcementInfo(enforcementInfo);
|
||||
lawCase.setStatus(Case.CaseStatus.filed);
|
||||
|
||||
// 保存案件信息
|
||||
Case savedCase = caseService.saveCase(lawCase);
|
||||
|
||||
// 断言保存成功
|
||||
assertNotNull(savedCase);
|
||||
assertNotNull(savedCase.getCaseId());
|
||||
assertEquals("测试执法案件", savedCase.getCaseName());
|
||||
assertNotNull(savedCase.getEnforcementInfo());
|
||||
// assertEquals("测试执法机构", savedCase.getEnforcementInfo().getAgency().getAgencyName());
|
||||
// assertEquals("测试企业", savedCase.getEnforcementInfo().getEnterprise().getUnitName());
|
||||
// assertEquals(FlowNode.filed, savedCase.getEnforcementInfo().getCurrentNodeCode());
|
||||
|
||||
// 测试转换为DTO
|
||||
DjbZfajxxRequestDto dto = new DjbZfajxxRequestDto();
|
||||
DjbZfajxxRequestDto convertedDto = dto.convert(savedCase);
|
||||
|
||||
// 断言DTO转换成功
|
||||
assertNotNull(convertedDto);
|
||||
assertEquals(savedCase.getCaseId(), convertedDto.getCaseId());
|
||||
assertEquals(savedCase.getCaseName(), convertedDto.getCaseName());
|
||||
assertEquals(savedCase.getCaseNum(), convertedDto.getCaseNum());
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue