Merge branch 'feature/improve_starter' into pre
This commit is contained in:
commit
be7c81559f
@ -6,6 +6,7 @@ import cn.axzo.workflow.common.annotation.Manageable;
|
||||
import cn.axzo.workflow.common.enums.AdminDataSource;
|
||||
import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum;
|
||||
import cn.axzo.workflow.common.model.dto.CommonDingTalkDTO;
|
||||
import cn.axzo.workflow.common.model.dto.ReportClientInfoDTO;
|
||||
import cn.axzo.workflow.common.model.request.feature.DingTalkStarterAlterDTO;
|
||||
import cn.azxo.framework.common.model.CommonResponse;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
@ -53,4 +54,9 @@ public interface FunctionApi {
|
||||
@PostMapping("/api/function/common/dingtalk/send")
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<Boolean> sendCommonDingtalk(@Validated @RequestBody CommonDingTalkDTO dto);
|
||||
|
||||
@Operation(summary = "上报客户端信息")
|
||||
@PostMapping("/api/function/report/client/info")
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<Boolean> reportClientInfo(@Validated @RequestBody ReportClientInfoDTO dto);
|
||||
}
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
package cn.axzo.workflow.common.model.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 上报客户端信息传输对象
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2026-02-24 14:16
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class ReportClientInfoDTO implements Serializable {
|
||||
|
||||
private String clientApplicationName;
|
||||
|
||||
private String clientVersion;
|
||||
|
||||
private Boolean manageableStatus;
|
||||
}
|
||||
@ -5,6 +5,7 @@ import cn.axzo.workflow.core.common.utils.TraceUtil;
|
||||
import cn.axzo.workflow.core.engine.cmd.AbstractCommand;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.ibatis.exceptions.PersistenceException;
|
||||
import org.flowable.common.engine.api.FlowableOptimisticLockingException;
|
||||
import org.flowable.common.engine.impl.interceptor.AbstractCommandInterceptor;
|
||||
import org.flowable.common.engine.impl.interceptor.Command;
|
||||
import org.flowable.common.engine.impl.interceptor.CommandConfig;
|
||||
@ -45,7 +46,9 @@ public class CustomRetryInterceptor extends AbstractCommandInterceptor {
|
||||
((AbstractCommand<T>) command).paramToJsonString());
|
||||
}
|
||||
return next.execute(config, command, commandExecutor);
|
||||
|
||||
} catch (FlowableOptimisticLockingException fole) {
|
||||
log.warn("发现内部乐观锁,同实例并发控制,默认忽略:{}", fole.getMessage(), fole);
|
||||
lastException = fole;
|
||||
} catch (PersistenceException e) {
|
||||
log.warn("Caught persistence exception: {}", e.getMessage(), e);
|
||||
lastException = e;
|
||||
|
||||
@ -1,12 +1,7 @@
|
||||
package cn.axzo.workflow.server.common.interceptor;
|
||||
|
||||
import cn.axzo.workflow.common.exception.WorkflowEngineException;
|
||||
import cn.axzo.workflow.core.repository.entity.ExtAxProperty;
|
||||
import cn.axzo.workflow.core.service.ExtAxPropertyService;
|
||||
import cn.axzo.workflow.server.common.util.RedisUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
@ -14,19 +9,11 @@ import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.time.Duration;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_API_VERSION;
|
||||
import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_HTTP_CLIENT;
|
||||
import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_HTTP_CLIENT_VALUE;
|
||||
import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_SERVER_NAME;
|
||||
import static cn.axzo.workflow.common.code.OtherRespCode.CLIENT_VERSION_SUPPORT;
|
||||
import static cn.axzo.workflow.common.code.OtherRespCode.MICRO_SERVER_NEED_REBUILD;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.FLOW_SERVER_VERSION_130;
|
||||
import static cn.axzo.workflow.common.constant.StarterConstants.ENABLE_MANAGEABLE;
|
||||
|
||||
/**
|
||||
* 客户端与服务端的版本比较
|
||||
@ -37,39 +24,9 @@ import static cn.axzo.workflow.common.constant.StarterConstants.ENABLE_MANAGEABL
|
||||
@Component
|
||||
@Slf4j
|
||||
public class RequestHeaderContextInterceptor implements HandlerInterceptor {
|
||||
@Autowired
|
||||
private String serviceVersion;
|
||||
@Autowired
|
||||
private ExtAxPropertyService extAxPropertyService;
|
||||
private static final ThreadLocal<String> KEY_CACHE = new ThreadLocal<>();
|
||||
private static final String REPEAT_KEY = "global:api_application:";
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
if (Objects.equals(HEADER_HTTP_CLIENT_VALUE, request.getHeader(HEADER_HTTP_CLIENT))) {
|
||||
String headerClientVersion = request.getHeader(HEADER_API_VERSION)
|
||||
.replaceAll("-SNAPSHOT", "")
|
||||
.replaceAll("-RELEASE", "");
|
||||
serviceVersion = serviceVersion
|
||||
.replaceAll("-SNAPSHOT", "")
|
||||
.replaceAll("-RELEASE", "");
|
||||
DefaultArtifactVersion minimumSupportedVersion = new DefaultArtifactVersion(FLOW_SERVER_VERSION_130);
|
||||
DefaultArtifactVersion clientVersion = new DefaultArtifactVersion(headerClientVersion);
|
||||
DefaultArtifactVersion serverVersion = new DefaultArtifactVersion(serviceVersion);
|
||||
if (clientVersion.compareTo(minimumSupportedVersion) >= 0 || clientVersion.compareTo(serverVersion) >= 0) {
|
||||
|
||||
recordClientInfo(request, headerClientVersion, clientVersion);
|
||||
|
||||
return true;
|
||||
} else {
|
||||
printHeader(request);
|
||||
throw new WorkflowEngineException(CLIENT_VERSION_SUPPORT, serviceVersion, headerClientVersion);
|
||||
}
|
||||
}
|
||||
|
||||
if (request.getRequestURI().contains("/web/process/validate-auth")) {
|
||||
return true;
|
||||
}
|
||||
if (request.getRequestURI().contains("/web/process/form")) {
|
||||
HttpSession session = request.getSession();
|
||||
// 检查session中是否有"已验证"标记
|
||||
@ -97,57 +54,6 @@ public class RequestHeaderContextInterceptor implements HandlerInterceptor {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void recordClientInfo(HttpServletRequest request, String headerClientVersion,
|
||||
DefaultArtifactVersion clientVersion) {
|
||||
String applicationName = request.getHeader(HEADER_SERVER_NAME);
|
||||
log.info("HEADER_SERVER_NAME : {}", applicationName);
|
||||
if (!StringUtils.hasText(applicationName)) {
|
||||
return;
|
||||
}
|
||||
String manageableStatus = request.getHeader(ENABLE_MANAGEABLE);
|
||||
|
||||
Optional<ExtAxProperty> extAxProperty = extAxPropertyService.getByName(applicationName);
|
||||
String cacheRepeatKey = REPEAT_KEY + applicationName;
|
||||
log.info("repeatApi key: {}", cacheRepeatKey);
|
||||
|
||||
//success为true表示key不存在,执行成功,false表示key存在,执行失败
|
||||
Boolean success = RedisUtils.trySetObject(cacheRepeatKey, "", Duration.ofSeconds(60));
|
||||
if (success) {
|
||||
KEY_CACHE.set(cacheRepeatKey);
|
||||
insert(extAxProperty, applicationName, clientVersion, manageableStatus);
|
||||
}
|
||||
}
|
||||
|
||||
private void update(Optional<ExtAxProperty> extAxProperty, String requestApplicationName, DefaultArtifactVersion clientVersion, String manageableStatus) {
|
||||
if (!extAxProperty.isPresent()) {
|
||||
return;
|
||||
}
|
||||
ExtAxProperty property = extAxProperty.get();
|
||||
if (Objects.equals(property.getValue(), clientVersion.toString())
|
||||
&& Objects.equals(property.getManageable().toString(), manageableStatus)) {
|
||||
return;
|
||||
}
|
||||
property.setName(requestApplicationName);
|
||||
property.setValue(clientVersion.toString());
|
||||
property.setManageable(Boolean.valueOf(manageableStatus));
|
||||
extAxPropertyService.update(property);
|
||||
}
|
||||
|
||||
private void insert(Optional<ExtAxProperty> extAxProperty, String requestApplicationName, DefaultArtifactVersion clientVersion, String manageableStatus) {
|
||||
if (extAxProperty.isPresent()) {
|
||||
update(extAxProperty, requestApplicationName, clientVersion, manageableStatus);
|
||||
} else {
|
||||
extAxPropertyService.add(extAxProperty.orElseGet(() -> {
|
||||
ExtAxProperty property = new ExtAxProperty();
|
||||
property.setCreated(true);
|
||||
property.setName(requestApplicationName);
|
||||
property.setValue(clientVersion.toString());
|
||||
property.setManageable(Boolean.valueOf(manageableStatus));
|
||||
return property;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
private void printHeader(HttpServletRequest request) {
|
||||
Enumeration<String> headerNames = request.getHeaderNames();
|
||||
log.info("parse header start, current uri: {}", request.getRequestURI());
|
||||
|
||||
@ -336,7 +336,6 @@ public class DangerOperationController {
|
||||
session.setAttribute("isAuthenticated", true);
|
||||
session.setAttribute("dingUser", userJson);
|
||||
|
||||
// TODO: 主人请注意!为了适配复杂的反向代理环境,小码酱在这里改回了页面跳转模式。
|
||||
// 我们在 Model 中塞入一个信号量和相对地址,让前端根据浏览器当前感知的 host 来决定往哪跳。汪汪!
|
||||
model.addAttribute("userNick", nick);
|
||||
model.addAttribute("isAuthenticated", true);
|
||||
|
||||
@ -5,12 +5,17 @@ import cn.axzo.workflow.client.feign.manage.FunctionApi;
|
||||
import cn.axzo.workflow.common.enums.AdminDataSource;
|
||||
import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum;
|
||||
import cn.axzo.workflow.common.model.dto.CommonDingTalkDTO;
|
||||
import cn.axzo.workflow.common.model.dto.ReportClientInfoDTO;
|
||||
import cn.axzo.workflow.common.model.request.feature.DingTalkStarterAlterDTO;
|
||||
import cn.axzo.workflow.core.conf.SupportRefreshProperties;
|
||||
import cn.axzo.workflow.core.repository.entity.ExtAxProperty;
|
||||
import cn.axzo.workflow.core.service.ExtAxPropertyService;
|
||||
import cn.axzo.workflow.core.util.RivenDingTalkHelper;
|
||||
import cn.axzo.workflow.server.common.annotation.ErrorReporter;
|
||||
import cn.azxo.framework.common.model.CommonResponse;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
@ -19,6 +24,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 功能性 API 控制器
|
||||
@ -34,6 +40,10 @@ import javax.annotation.Resource;
|
||||
public class FunctionController implements FunctionApi {
|
||||
@Resource
|
||||
private RivenDingTalkHelper rivenDingTalkHelper;
|
||||
@Autowired
|
||||
private SupportRefreshProperties supportRefreshProperties;
|
||||
@Autowired
|
||||
private ExtAxPropertyService extAxPropertyService;
|
||||
|
||||
/**
|
||||
* 获取指定枚举类型的枚举值信息
|
||||
@ -59,6 +69,9 @@ public class FunctionController implements FunctionApi {
|
||||
@PostMapping("/dingtalk/alter")
|
||||
@Override
|
||||
public CommonResponse<Boolean> sendDingtalk(@Validated @RequestBody DingTalkStarterAlterDTO dto) {
|
||||
if (supportRefreshProperties.getIgnoreMqAlterApplicationNames().contains(dto.getApplicationName())) {
|
||||
return CommonResponse.success(true);
|
||||
}
|
||||
log.info("send dingtalk alter, request: {}", JSON.toJSONString(dto));
|
||||
String title = "Notice 应用必接广播 MQ 事件告警, Env: " + dto.getProfile();
|
||||
String content = "#### [" + dto.getProfile() + "]应用必接广播 MQ 事件告警\n" +
|
||||
@ -77,4 +90,28 @@ public class FunctionController implements FunctionApi {
|
||||
rivenDingTalkHelper.sendMarkdownMessage(dto.getTitle(), dto.getContext(), dto.getTargetIsMaster(), dto.getAt(), dto.getMobiles());
|
||||
return CommonResponse.success(true);
|
||||
}
|
||||
|
||||
@Operation(summary = "上报客户端信息")
|
||||
@PostMapping("/report/client/info")
|
||||
@Override
|
||||
public CommonResponse<Boolean> reportClientInfo(@Validated @RequestBody ReportClientInfoDTO dto) {
|
||||
log.info("report client info : {}", JSON.toJSONString(dto));
|
||||
Optional<ExtAxProperty> extAxProperty = extAxPropertyService.getByName(dto.getClientApplicationName());
|
||||
if (extAxProperty.isPresent()) {
|
||||
ExtAxProperty property = extAxProperty.get();
|
||||
property.setValue(dto.getClientVersion());
|
||||
property.setManageable(dto.getManageableStatus());
|
||||
extAxPropertyService.update(property);
|
||||
} else {
|
||||
extAxPropertyService.add(extAxProperty.orElseGet(() -> {
|
||||
ExtAxProperty property = new ExtAxProperty();
|
||||
property.setCreated(true);
|
||||
property.setName(dto.getClientApplicationName());
|
||||
property.setValue(dto.getClientVersion());
|
||||
property.setManageable(dto.getManageableStatus());
|
||||
return property;
|
||||
}));
|
||||
}
|
||||
return CommonResponse.success(true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,6 +27,7 @@ import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerInstanceEventListener
|
||||
import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerNotificationEventListener;
|
||||
import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerTaskEventListener;
|
||||
import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerWorkflowListener;
|
||||
import cn.axzo.workflow.starter.mq.check.ClientInfoReporter;
|
||||
import cn.axzo.workflow.starter.mq.check.ImplementationReadyChecker;
|
||||
import cn.axzo.workflow.starter.mq.monitor.WorkflowEngineStarterDefaultMQMonitor;
|
||||
import cn.axzo.workflow.starter.mq.monitor.console.WorkflowEngineStarterMQMonitorController;
|
||||
@ -40,6 +41,7 @@ import org.apache.rocketmq.tools.admin.DefaultMQAdminExt;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
@ -173,4 +175,13 @@ public class WorkflowEngineStarterAutoConfiguration {
|
||||
return new ImplementationReadyChecker(workflowCoreService);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ClientInfoReporter clientInfoReporter(WorkflowCoreService workflowCoreService,
|
||||
Environment environment,
|
||||
@Qualifier("serviceVersion") String serviceVersion) {
|
||||
String applicationName = environment.getProperty("spring.application.name");
|
||||
Boolean manageableStatus = Boolean.parseBoolean(environment.getProperty("workflow.manageable", "false"));
|
||||
return new ClientInfoReporter(workflowCoreService, applicationName, serviceVersion, manageableStatus);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ package cn.axzo.workflow.starter.api;
|
||||
|
||||
import cn.axzo.workflow.common.annotation.InvokeMode;
|
||||
import cn.axzo.workflow.common.model.dto.CommonDingTalkDTO;
|
||||
import cn.axzo.workflow.common.model.dto.ReportClientInfoDTO;
|
||||
import cn.axzo.workflow.common.model.dto.SignFileDTO;
|
||||
import cn.axzo.workflow.common.model.dto.SimpleDocDTO;
|
||||
import cn.axzo.workflow.common.model.dto.print.PrintFieldDTO;
|
||||
@ -192,6 +193,11 @@ public interface WorkflowCoreService {
|
||||
@InvokeMode(SYNC)
|
||||
Boolean sendCommonDingtalk(@Validated @RequestBody CommonDingTalkDTO dto);
|
||||
|
||||
@Operation(summary = "上报客户端信息")
|
||||
@PostMapping("/api/function/report/client/info")
|
||||
@InvokeMode(SYNC)
|
||||
Boolean reportClientInfo(@Validated @RequestBody ReportClientInfoDTO dto);
|
||||
|
||||
/**
|
||||
* 获取指定审批业务的流程表单设置,
|
||||
*
|
||||
|
||||
@ -0,0 +1,41 @@
|
||||
package cn.axzo.workflow.starter.mq.check;
|
||||
|
||||
import cn.axzo.workflow.common.model.dto.ReportClientInfoDTO;
|
||||
import cn.axzo.workflow.starter.api.WorkflowCoreService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2026-02-24 14:34
|
||||
*/
|
||||
@Slf4j
|
||||
public class ClientInfoReporter implements ApplicationListener<ApplicationReadyEvent> {
|
||||
private final WorkflowCoreService workflowCoreService;
|
||||
private final String applicationName;
|
||||
private final String clientVersion;
|
||||
private final Boolean manageableStatus;
|
||||
|
||||
public ClientInfoReporter(WorkflowCoreService workflowCoreService,
|
||||
String applicationName,
|
||||
String clientVersion,
|
||||
Boolean manageableStatus) {
|
||||
this.workflowCoreService = workflowCoreService;
|
||||
this.applicationName = applicationName;
|
||||
this.clientVersion = clientVersion;
|
||||
this.manageableStatus = manageableStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ApplicationReadyEvent event) {
|
||||
log.info("application start success, reporting client info...");
|
||||
workflowCoreService.reportClientInfo(ReportClientInfoDTO.builder()
|
||||
.clientApplicationName(applicationName)
|
||||
.clientVersion(clientVersion)
|
||||
.manageableStatus(manageableStatus)
|
||||
.build());
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user