Files
contract-manager/src/main/java/com/ecep/contract/manager/SpringApp.java
songqq 6711657663 feat(u8): 添加用友U8配置窗口和数据迁移功能
新增用友U8配置窗口,支持日期和文本配置项的编辑与保存。实现从CloudInfo到CloudYu的数据迁移任务,优化任务执行方式。重构多个同步任务类继承Tasker基类,统一任务处理逻辑。扩展YongYouU8Service功能,添加配置相关接口。调整UI布局和菜单项,增加配置入口。

refactor: 重命名CompanyTableCell为EmployeeRoleTableCell

style: 清理无用导入和格式化代码

fix: 修复ContractTypeSyncTask中分类和方向字段设置错误
2025-08-25 18:57:17 +08:00

263 lines
11 KiB
Java

package com.ecep.contract.manager;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import java.util.Properties;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ScheduledExecutorService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.boot.ConfigurableBootstrapContext;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationHook;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
import org.springframework.boot.context.metrics.buffering.StartupTimeline;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.metrics.StartupStep;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import com.ecep.contract.manager.cloud.CloudRepositoriesConfig;
import com.ecep.contract.manager.ds.DsRepositoriesConfig;
import com.ecep.contract.manager.ui.MessageHolder;
import com.ecep.contract.manager.util.MyDateTimeUtils;
import com.ecep.contract.manager.util.UITools;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
@SpringBootApplication(exclude = { org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration.class })
@EnableScheduling
@EnableAsync
@EnableCaching
public class SpringApp {
private static final Logger logger = LoggerFactory.getLogger(SpringApp.class);
static SpringApplication application;
static ConfigurableApplicationContext context;
public static <T> T getBean(Class<T> requiredType) throws BeansException {
return context.getBean(requiredType);
}
public static void launch(Properties properties, MessageHolder holder) {
application = new SpringApplication(SpringApp.class);
BufferingApplicationStartup startup = new BufferingApplicationStartup(2000);
application.setApplicationStartup(startup);
//
holder.debug("应用程序环境准备中...");
SpringApplication.withHook(new Hook(holder), () -> {
// 动态地注册或修改这些组件和配置
application.addBootstrapRegistryInitializer(registry -> {
//
System.out.println("registry = " + registry);
});
application.addListeners(event -> {
logger.debug("SpringApp.launch ApplicationListener, event:{}", event);
});
application.addInitializers(app -> {
logger.debug("SpringApp.launch ApplicationContextInitializer");
ConfigurableEnvironment environment = app.getEnvironment();
logger.debug("environment = {}", environment);
PropertySource<?> dynamicProperties = environment.getPropertySources().get("dynamicProperties");
if (dynamicProperties != null) {
logger.debug("dynamicProperties = {}", dynamicProperties);
}
environment.getPropertySources().addLast(new PropertiesPropertySource("dynamicProperties", properties));
// app.getBeanFactory().registerSingleton("dataSource", dataSource());
logger.debug("app = {}", app);
if (app instanceof AnnotationConfigApplicationContext ctx) {
ctx.register(DsRepositoriesConfig.class);
ctx.register(CloudRepositoriesConfig.class);
}
});
startup.start("");
context = application.run();
logger.debug("SpringApp.launch application.run().");
Duration between = Duration.between(startup.getBufferedTimeline().getStartTime(), Instant.now());
holder.info("应用程序环境加载完成... " + between);
});
CompletableFuture.runAsync(() -> {
// 在这里调用 startup 性能分析
analyzeStartupPerformance(startup);
}, Desktop.instance.getExecutorService());
}
/**
* 分析启动性能数据并输出到日志
*/
private static void analyzeStartupPerformance(BufferingApplicationStartup startup) {
// 获取所有记录的事件
StartupTimeline timeline = startup.getBufferedTimeline();
if (timeline == null || timeline.getEvents().isEmpty()) {
logger.warn("StartupTimeline 为空或没有事件!");
return;
}
logger.info("总共有 {} 个事件", timeline.getEvents().size());
// 找出与 Bean 初始化相关的步骤
timeline.getEvents().stream()
.filter(event -> event.getStartupStep().getName().startsWith("spring.beans."))
.sorted((a, b) -> Long.compare(b.getDuration().toMillis(), a.getDuration().toMillis()))
.limit(30)
.forEach(event -> {
String name = event.getStartupStep().getName();
long duration = event.getDuration().toMillis();
logger.info("Bean 初始化阶段: {} - 耗时: {} ms", name, duration);
for (StartupStep.Tag tag : event.getStartupStep().getTags()) {
if ("beanName".equals(tag.getKey())) {
logger.info(" └── Bean 名称: {}", tag.getValue());
}
}
});
}
public static String getMessage(String code, Object[] args, Locale locale) {
return context.getMessage(code, args, locale);
}
public static void shutdown() {
System.out.println("SpringApp.shutdown");
if (logger.isDebugEnabled()) {
logger.debug("shutdown");
}
if (context != null) {
if (context.isRunning()) {
context.close();
}
}
}
public static boolean isRunning() {
return context != null && context.isRunning();
}
static class Hook implements SpringApplicationHook, SpringApplicationRunListener {
MessageHolder holder;
Hook(MessageHolder holder) {
this.holder = holder;
}
public void debug(String msg) {
holder.debug(msg);
}
@Override
public void starting(ConfigurableBootstrapContext bootstrapContext) {
logger.debug("Desktop.starting");
debug("Spring Application 启动中...");
}
@Override
public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext,
ConfigurableEnvironment environment) {
logger.debug("Desktop.environmentPrepared");
debug("初始化 Environment 中,请稍后...");
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
logger.debug("Desktop.contextPrepared");
debug("Spring Application Context 预处理中,请稍后...");
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
logger.debug("Desktop.contextLoaded");
debug("Spring Application Context 初始化完毕,请稍后...");
}
@Override
public void started(ConfigurableApplicationContext context, Duration timeTaken) {
logger.debug("Desktop.started");
debug("Spring Application 启动完毕.");
}
@Override
public void ready(ConfigurableApplicationContext context, Duration timeTaken) {
logger.debug("Desktop.ready");
debug("Spring Application ready.");
}
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
logger.error("Desktop.failed", exception);
holder.error("Spring Application 启动失败(" + exception.getMessage() + ").");
UITools.showExceptionAndWait("启动失败", exception);
}
@Override
public SpringApplicationRunListener getRunListener(SpringApplication springApplication) {
return this;
}
}
@EventListener
public void handleClosedEvent(ContextClosedEvent event) {
if (logger.isDebugEnabled()) {
logger.debug("handleClosedEvent={}", event);
}
Desktop.shutdown();
}
@Bean
public CacheManager cacheManager() {
// return new ConcurrentMapCacheManager("myCache");
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
cacheManager.setAsyncCacheMode(true);
return cacheManager;
}
@Bean
public ObjectMapper objectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ISO_LOCAL_DATE));
javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(
DateTimeFormatter.ofPattern(MyDateTimeUtils.DEFAULT_DATETIME_FORMAT_PATTERN)));
javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ISO_LOCAL_DATE));
javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(
DateTimeFormatter.ofPattern(MyDateTimeUtils.DEFAULT_DATETIME_FORMAT_PATTERN)));
javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ISO_LOCAL_TIME));
objectMapper.registerModule(javaTimeModule);
return objectMapper;
}
@Bean
public ScheduledExecutorService scheduledExecutorService() {
return Desktop.instance.getExecutorService();
}
}