问题描述
我正在使用Spring Boot应用程序,在其中创建了一些REST API。有一个Readings实体,Alert实体。我正在通过POST方法发送读数,并且在postReadings
类的ReadingsService
方法中,我正在使用KIE
检查读数是否符合特定条件,并在{{1 }}文件。我正在创建一个Alert对象,并使用rules.drl
方法将其设置为全局对象。然后,我要检查Alert对象是否为null并将其保存到Alert Repository。在drools文件中,我添加了一条打印语句,以检查是否正确创建了所有警报。所有警报都可以通过print语句正确打印,但是,只有其中一部分被保存到警报存储库中。谁能帮忙吗?
这是ReadingsService
session.setGlobal
这是流口水文件
@Service
public class ReadingsServiceImpl implements ReadingsService{
@Autowired
ReadingsRepository repository;
@Autowired
VehicleRepository vehicleRepo;
@Autowired
private KieSession session;
@Autowired
AlertRepository alertRepo;
@Override
public List<Readings> findAll() {
return repository.findAll();
}
@Override
public Readings postReadings(Readings readings) {
Alert alert = new Alert();
session.setGlobal("alert",alert);
session.insert(readings);
session.fireAllRules();
if(!Optional.ofNullable(alert).map(o -> o.getVin()).orElse("").isBlank()) {
alertRepo.save(alert);
}
return repository.save(readings);
}
解决方法
您的规则没有错。但是,您的保存受“ if”语句保护,该语句检查是否存在非空白/非空VIN,因此很可能会导致缺少保存的问题:
if(!Optional.ofNullable(alert).map(o -> o.getVin()).orElse("").isBlank()) {
alertRepo.save(alert);
}
您可以轻松地编写单元测试来验证此行为-如果警报存在(因为您使用相同的方法更早地实例化了警报,所以一直存在)并且有VIN,则可以保存;并且如果警报存在并且没有VIN,则不会保存该警报。
这是保存规则输出的非常老式的方法。如今,我们通常会在右侧规则中使用具有副作用的动作,或使用对象来传递信息。
您当前的设置甚至存在逻辑缺陷:您将总是具有警报,因为在将其添加到会话之前实例化了它。
如果要使用这样的全局变量,则需要向Alert类本身添加某种指示符,以指示已添加警报。因此,例如,如果您仅添加带有适当的getter的boolean added = false
方法,则可以像这样更新规则:
rule "Engine Coolant Or Check Engine Light"
when
readingsObject: Readings(engineCoolantLow || checkEngineLightOn);
then
alert.setAdded(true); // Mark the alert as now being added
alert.setVin(readingsObject.getVin());
alert.setPriotity("LOW");
alert.setDescription("Engine Coolant LOW Or Check Engine Light ON");
alert.setTimestamp(readingsObject.getTimestamp());
alert.setLatitude(readingsObject.getLatitude());
alert.setLongitude(readingsObject.getLongitude());
System.out.println(alert.toString());
end
然后您可以将调用方法固定为 not ,以取消非null对象的可为空性,而改为取消是否已添加警报:
public Readings postReadings(Readings readings) {
Alert alert = new Alert();
session.setGlobal("alert",alert);
session.insert(readings);
session.fireAllRules();
if(alert.isAdded()) {
alertRepo.save(alert);
}
return repository.save(readings);
}
(当然,我假设您在“存储库”实例中具有适当的连接和事务处理。)
如果您仍然需要非空VIN,则应在规则的左侧进行检查;像这样的东西:
readingsObject: Readings( vin != null,engineCoolantLow || checkEngineLightOn )
相关问题:How to return the value from Cosequence of drl file to java
, Drools会在同一(单个)线程中评估规则,除非您进行其他配置。因此postReadings()
和drools然后阻塞将由同一线程调用。但是postReadings()
可以在并发上下文中执行,并且使用共享的全局对象引用Alert alert
(由于共享的会话实例)。 Drools与使ReadingsServiceImpl
线程安全的一般问题无关。实现这一目标的方法有很多,第一个反模式是“全局变量” ...不要在drools文件中使用共享对象,而要使用共享线程安全服务参考。您可以使用不同的同步方法,使用线程局部变量来使您的服务以线程安全的方式处理内部事务,但是您是否真的需要共享对象?
import com.shiva.truckerapi.entity.Readings;
import com.shiva.truckerapi.entity.Alert;
global com.shiva.truckerapi.service.ReadingsService readingsService;
rule "EngineCoolantOrCheckEngineLight"
when
readingsObject: Readings(engineCoolantLow || checkEngineLightOn);
then
Alert alert = new Alert();
alert.setVin(readingsObject.getVin());
alert.setPriotity("LOW");
alert.setDescription("Engine Coolant LOW Or Check Engine Light ON");
alert.setTimestamp(readingsObject.getTimestamp());
alert.setLatitude(readingsObject.getLatitude());
alert.setLongitude(readingsObject.getLongitude());
System.out.println(alert.toString());
readingsService.onAlert(alert);
end;
服务变更
@PostConstruct
private void postConstruct() {
session.setGlobal("readingsService",this);
}
@Override
public void postReadings(Readings readings) {
session.insert(readings);
session.fireAllRules();
repository.save(readings);
}
@Override
public void onAlert(Alert alert) {
// this looks ugly. There should not be produced 'invalid' alert,if vin is empty alert should not be generated by the rule itself
if(!Optional.ofNullable(alert).map(o -> o.getVin()).orElse("").isBlank()) {
alertRepo.save(alert);
}
}