java - 使用 HTTP 调用启动 Spring 状态机
问题描述
我想使用 HTTP POST 触发从 Papyrus 加载的 Spring State Machine 模型。如果我{"state_machine":"START"}
通过 HTTP 发送,我想启动预定义的状态机模型。这可能吗?或者从不同的角度来看,是否可以在 Spring State Machine 模型中创建和运行 REST API?
我正在使用带有 Spring State Machine 依赖项的 Spring Boot。Swagger 上有定义的端点来发送 HTTP POST 到服务类。
它基于这个项目,您可以在其中检查状态机/s 的所有代码,因为我基本上只想将 HTTP 调用集成到它。
考虑到第 65 行的 Service 类的 Spring Statemachine,我得到 NullPointerException,即stateMachineOne = this.stateMachineFactory.getStateMachine("machineone");
. 这是完整的例外:
java.lang.NullPointerException
at test.umlspringstatemachine.SSMService.RunSSM(SSMService.java:65)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.apache.camel.support.ObjectHelper.invokeMethodSafe(ObjectHelper.java:372)
at org.apache.camel.component.bean.MethodInfo.invoke(MethodInfo.java:494)
at org.apache.camel.component.bean.MethodInfo$1.doProceed(MethodInfo.java:316)
at org.apache.camel.component.bean.MethodInfo$1.proceed(MethodInfo.java:286)
at org.apache.camel.component.bean.AbstractBeanProcessor.process(AbstractBeanProcessor.java:146)
at org.apache.camel.component.bean.BeanProcessor.process(BeanProcessor.java:81)
at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler$RedeliveryTask.doRun(RedeliveryErrorHandler.java:780)
at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler$RedeliveryTask.run(RedeliveryErrorHandler.java:688)
at org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.schedule(DefaultReactiveExecutor.java:181)
at org.apache.camel.impl.engine.DefaultReactiveExecutor.scheduleMain(DefaultReactiveExecutor.java:62)
at org.apache.camel.processor.Pipeline.process(Pipeline.java:167)
at org.apache.camel.impl.engine.CamelInternalProcessor.process(CamelInternalProcessor.java:388)
at org.apache.camel.impl.engine.DefaultAsyncProcessorAwaitManager.process(DefaultAsyncProcessorAwaitManager.java:83)
at org.apache.camel.support.AsyncProcessorSupport.process(AsyncProcessorSupport.java:41)
at org.apache.camel.http.common.CamelServlet.doExecute(CamelServlet.java:319)
at org.apache.camel.http.common.CamelServlet.doService(CamelServlet.java:214)
at org.apache.camel.http.common.CamelServlet.service(CamelServlet.java:130)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:373)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1590)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:829)
我对该项目所做的更改是我从中删除了下一部分代码,UmlSpringStateMachineApplication.java
因此当我启动整个应用程序时状态机不会启动:
@Override
public void run(String... args) throws Exception {
synchronized (stateMachineOne) {
stateMachineOne.getExtendedState().getVariables().put("foo", "machine1");
stateMachineOne.start();
}
synchronized (stateMachineTwo) {
if(stateMachineOne.isComplete()) {
stateMachineTwo.getExtendedState().getVariables().put("foo", (String)stateMachineOne.getExtendedState().getVariables().get("foo"));
stateMachineTwo.start();
}
}
}
在 Service 类中,我在下面有类似这样的内容,但是我得到了空异常,例如 Spring State Machine 上下文或缺少某些内容。我想收到来自 HTTP POST 的信息stateMachineOne.start();
。START
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.camel.Exchange;
import org.apache.camel.Message;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.config.StateMachineFactory;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class SSMService {
@Autowired
private StateMachineFactory<String, String> stateMachineFactory;
@Autowired
private StateMachine<String, String> stateMachineOne;
public SSMService() {
}
public void TriggerSSM(Exchange exchange) {
Message camelMessage = exchange.getIn();
ObjectMapper mapObject = new ObjectMapper();
Map<String, Object> mapObj = mapObject.convertValue(camelMessage.getBody(), Map.class);
try {
JSONObject json = new JSONObject(mapObj);
String state_machine= json.getString("state_machine");
if (state_machine.equals("START")) {
stateMachineOne = this.stateMachineFactory.getStateMachine("machineone");
stateMachineOne.getExtendedState().getVariables().put("foo", "machine1");
stateMachineOne.start();
}
}
} catch (JsonProcessingException | JSONException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
这是配置类:
import ch.qos.logback.classic.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.statemachine.config.EnableStateMachine;
import org.springframework.statemachine.config.StateMachineConfigurerAdapter;
import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer;
import org.springframework.statemachine.config.builders.StateMachineModelConfigurer;
import org.springframework.statemachine.config.model.StateMachineModelFactory;
import org.springframework.statemachine.listener.StateMachineListener;
import org.springframework.statemachine.listener.StateMachineListenerAdapter;
import org.springframework.statemachine.state.State;
import org.springframework.statemachine.uml.UmlStateMachineModelFactory;
import org.springframework.statemachine.config.EnableStateMachineFactory;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Configuration
//@EnableStateMachineFactory
@EnableStateMachine(name="stateMachineOne")
public class StateMachineOneConfig extends StateMachineConfigurerAdapter<String, String> {
Logger log;
@Override
public void configure(StateMachineConfigurationConfigurer<String, String> config) throws Exception {
config.withConfiguration().autoStartup(false).listener(listener1()).machineId("machineone");
}
@Override
public void configure(StateMachineModelConfigurer<String, String> model) throws Exception {
model.withModel().factory(modelFactory1());
}
@Bean
public StateMachineModelFactory<String, String> modelFactory1() {
return new UmlStateMachineModelFactory("classpath:papyrus/StateMachine1.uml");
}
@Bean
public StateMachineListener<String, String> listener1() {
return new StateMachineListenerAdapter<String, String>() {
@Override
public void stateChanged(State<String, String> from, State<String, String> to) {
log.info("State 1 changed to " + to.getId());
}
};
}
}
这是带有依赖项的 pom.xml 文件:
<?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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>test</groupId>
<artifactId>camel</artifactId>
<packaging>jar</packaging>
<version>1.0</version>
<name>Camel - OpenAPI - Spring State Machine</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring.boot-version>2.3.0.RELEASE</spring.boot-version>
<jackson.swagger.version>2.12.0</jackson.swagger.version>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<start-class>test.umlspringstatemachine.UmlSpringStateMachineApplication</start-class>
</properties>
<dependencyManagement>
<dependencies>
<!-- Spring Boot BOM -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring.boot-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Camel BOM -->
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-spring-boot-dependencies</artifactId>
<version>3.9.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.statemachine</groupId>
<artifactId>spring-statemachine-core</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.statemachine</groupId>
<artifactId>spring-statemachine-uml</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.statemachine</groupId>
<artifactId>spring-statemachine-autoconfigure</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.statemachine</groupId>
<artifactId>spring-statemachine-data-jpa</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
<!-- Spring Boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- Camel -->
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-stream-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-jackson-starter</artifactId>
</dependency>
<!-- REST -->
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-rest-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-servlet-starter</artifactId>
</dependency>
<!-- Swagger -->
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-swagger-java-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-rest-swagger-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-swagger-java</artifactId>
<version>3.9.0</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>swagger-ui</artifactId>
<version>3.51.2</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>webjars-locator</artifactId>
<version>0.42</version>
</dependency>
<!-- Kafka -->
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-kafka</artifactId>
<version>3.9.0</version>
</dependency>
<!-- JSON -->
<dependency>
<groupId>org.codehaus.jettison</groupId>
<artifactId>jettison</artifactId>
<version>1.4.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.0</version>
<executions>
<execution>
<id>default-prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>default-report</id>
<phase>prepare-package</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- OWASP Dependency Check - https://www.owasp.org/index.php/OWASP_Dependency_Check -->
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>3.0.2</version>
<configuration>
<format>XML</format>
<outputDirectory>${dependency.check.report.dir}</outputDirectory>
</configuration>
</plugin>
</plugins>
</build>
</project>
解决方案
我克隆了您的项目并进行了一些更改以使其正常工作,主要的可以在此处列出:
1- 向主类添加组件扫描,以便能够找到状态机配置 bean(包括包重命名)。摆脱 SSM 自定义服务并更改为使用您的自定义实现
@SpringBootApplication
@ComponentScan(basePackages = {"uml.statemachine.*"})
public class UmlSpringStateMachineApplication implements CommandLineRunner
@Autowired
private SSMService stateMachineService;
2-样板逻辑根据您想要的类型获取机器
@Component
public class SSMService {
@Autowired
@Qualifier(value="config_one")
private StateMachineFactory<String, String> stateMachineFactoryOne;
@Autowired
@Qualifier(value="config_two")
private StateMachineFactory<String, String> stateMachineFactoryTwo;
public SSMService() {
}
public StateMachine<String, String> acquireMachine(String id, String version){
if (version.equals("one")){
return stateMachineFactoryOne.getStateMachine(id);
}
else{
return stateMachineFactoryTwo.getStateMachine(id);
}
}
3- 由于注入问题而注释掉 StateMachineServiceConfig(您可以进一步查看)
4-替换为您的配置类中的工厂注释
@Configuration
@EnableStateMachineFactory(name = "config_one")
public class StateMachineOneConfig
extends StateMachineConfigurerAdapter<String, String> {
5-在我的情况下,项目没有编译,所以我不得不在你的 pom 中包含一些额外的依赖项(可能没有必要)
<repositories>
<repository>
<id>spring-snapshots</id>
<url>http://repo.spring.io/snapshot</url>
<snapshots><enabled>true</enabled></snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<url>http://repo.spring.io/milestone</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-snapshots</id>
<url>http://repo.spring.io/snapshot</url>
</pluginRepository>
<pluginRepository>
<id>spring-milestones</id>
<url>http://repo.spring.io/milestone</url>
</pluginRepository>
</pluginRepositories>
您可以在我为帮助您而创建的存储库中找到更改列表
https://github.com/Daanielvb/state-machine-papyrus-help
希望这会有所帮助
推荐阅读
- c# - 日期转换问题
- rest - 在 Spring Boot API 上实现 JWT 身份验证
- go - 如何实现我自己的文件类型?
- c++ - 将g ++编译器标志更改为-std = c ++ 11时,犰狳+ make的分段错误
- python - 我想将一个按钮从我的 UI 连接到我的 python 代码。
- python - 如何使图像随机出现和消失?
- sql - 有条件地在其他列上从配置单元表中获取最新列值
- elasticsearch - ES 不同分数查询 vs query_string
- kentico - 安装 Kentico 后无法使用默认用户名管理员登录
- python-3.x - 登录网站,然后在 Python3 中的 BeautifulSoup4 中获取 asp 数据