欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 焦点 > Spring Boot项目集成Aviator实现成本计算模块

Spring Boot项目集成Aviator实现成本计算模块

2025/5/7 17:37:57 来源:https://blog.csdn.net/llg3189609554/article/details/147731321  浏览:    关键词:Spring Boot项目集成Aviator实现成本计算模块

Spring Boot项目集成Aviator实现表达式动态成本计算功能的完整解决方案


一、Maven依赖配置

<!-- aviator核心库 -->
<dependency><groupId>com.googlecode.aviator</groupId> <artifactId>aviator</artifactId><version>5.3.3</version>
</dependency><!-- 校验框架 -->
<dependency><groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

二、配置类设计

1. Aviator引擎配置
@Configuration 
public class AviatorConfig {@Bean public AviatorEvaluatorInstance aviatorEvaluator() {AviatorEvaluatorInstance instance = AviatorEvaluator.newInstance(); // 配置引擎参数 instance.setOption(Options.USE_USER_ENV_AS_TOP_ENV_DIRECTLY,  true);instance.setOption(Options.MAX_CACHE_SIZE,  1000);  // 表达式缓存数量 instance.setOption(Options.TRACE_EVAL,  false);    // 生产环境关闭调试 return instance;}
}
2. 成本规则加载配置
@Configuration 
@ConfigurationProperties(prefix = "cost.rules") 
public class CostRuleConfig {// 规则文件存储路径 private String location = "classpath:rules/cost";// 规则映射表(示例:{ruleKey: 规则文件名})private Map<String, String> mapping = new HashMap<>();// Getter/Setter 
}

三、领域模型设计

1. 成本计算请求DTO
@Data 
@NoArgsConstructor 
@AllArgsConstructor 
public class CostCalculateRequest {@NotBlank(message = "成本类型不能为空")private String costType;  // 对应规则类型如:hardware/software @NotNull(message = "计算参数不能为空")private Map<String, Object> params;  // 输入参数如数量、单价等 
}
2. 统一响应DTO
@Data 
@AllArgsConstructor 
public class ApiResponse<T> {private int code;private String message;private T data;public static <T> ApiResponse<T> success(T data) {return new ApiResponse<>(200, "Success", data);}
}

四、业务层实现

1. 表达式加载策略接口
public interface ExpressionLoader {/*** 加载指定规则表达式 * @param ruleKey 规则标识 * @return 编译后的表达式 */Expression loadExpression(String ruleKey);
}
2. 文件系统实现(示例)
@Component 
@RequiredArgsConstructor 
public class FileExpressionLoader implements ExpressionLoader {private final CostRuleConfig ruleConfig;private final AviatorEvaluatorInstance evaluator;@Override public Expression loadExpression(String ruleKey) {String fileName = ruleConfig.getMapping().get(ruleKey); try {Resource resource = new ClassPathResource(ruleConfig.getLocation()  + "/" + fileName);return evaluator.compile(resource.getFile().getAbsolutePath(),  true);} catch (IOException e) {throw new BusinessException("规则文件加载失败: " + fileName);}}
}
3. 核心计算服务
@Service 
@RequiredArgsConstructor 
public class CostCalculatorService {private final ExpressionLoader loader;private final AviatorEvaluatorInstance evaluator;/*** 执行成本计算 * @param request 计算请求 * @return 计算结果(包含明细)*/public BigDecimal calculateCost(CostCalculateRequest request) {// 1. 加载表达式 Expression exp = loader.loadExpression(request.getCostType()); // 2. 构建计算环境 Map<String, Object> env = new HashMap<>(request.getParams()); env.put("log",  Math::log);  // 注入数学函数 // 3. 执行计算 Object result = exp.execute(env); // 4. 结果转换 if (result instanceof Number) {return new BigDecimal(result.toString()).setScale(2,  RoundingMode.HALF_UP);}throw new BusinessException("计算结果类型异常");}
}

五、控制层实现

@RestController 
@RequestMapping("/api/cost")
@RequiredArgsConstructor 
public class CostController {private final CostCalculatorService calculator;@PostMapping("/calculate")public ApiResponse<BigDecimal> calculate(@Valid @RequestBody CostCalculateRequest request) {try {BigDecimal result = calculator.calculateCost(request); return ApiResponse.success(result); } catch (BusinessException e) {return new ApiResponse<>(400, e.getMessage(),  null);}}
}

六、规则文件示例

创建 resources/rules/cost/hardware.av

## 硬件成本计算规则 
let {quantity = params.quantity, unit_price = params.unitPrice, discount = params.discount  ?: 1.0  # 默认不打折 
};# 计算逻辑:数量*单价*折扣 + 固定运输成本 
total = quantity * unit_price * discount + 500;# 返回结果 
return total;

七、异常处理增强

@ControllerAdvice 
public class GlobalExceptionHandler {@ExceptionHandler(BusinessException.class) @ResponseStatus(HttpStatus.BAD_REQUEST)@ResponseBody public ApiResponse<Void> handleBusinessException(BusinessException ex) {return new ApiResponse<>(400, ex.getMessage(),  null);}@ExceptionHandler({ExpressionSyntaxErrorException.class,  ExpressionRuntimeException.class}) @ResponseStatus(HttpStatus.BAD_REQUEST)@ResponseBody public ApiResponse<Void> handleAviatorException(Exception ex) {return new ApiResponse<>(400, "规则执行错误: " + ex.getMessage(),  null);}
}

八、安全增强配置

application.yml 中添加:

yaml复制aviator:security:max-loop-count: 10000    # 防止死循环 forbidden-classes:       # 禁用危险类 - java.lang.System  - java.lang.Runtime  max-expression-length: 5000  # 限制表达式长度 

九、性能优化建议

  1. 表达式缓存:利用Aviator内置的编译缓存(已通过compile方法的第二个参数启用)
  2. 预热加载:在应用启动时预加载高频规则
java复制@EventListener(ApplicationReadyEvent.class) 
public void preloadHotRules() {List<String> hotRules = Arrays.asList("hardware",  "software");hotRules.forEach(rule  -> calculator.calculateCost(new  CostCalculateRequest(rule, new HashMap<>())));
}
  1. 监控埋点:通过Spring Actuator暴露指标
@Bean 
public MeterRegistryCustomizer<MeterRegistry> aviatorMetrics() {return registry -> registry.config().commonTags("module",  "cost-calculation");
}

十、验证测试用例

@SpringBootTest 
public class CostCalculatorTest {@Autowired private CostCalculatorService calculator;@Test void testHardwareCost() {Map<String, Object> params = Map.of( "quantity", 100,"unitPrice", 250.5,"discount", 0.9 );BigDecimal result = calculator.calculateCost( new CostCalculateRequest("hardware", params));assertEquals(new BigDecimal("23045.00"), result);}
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词