文档章节

MVEL实现java直接根据公式计算结果

V
 ValSong
发布于 2017/09/06 22:53
字数 651
阅读 52
收藏 3
点赞 0
评论 0

工具类

import java.math.BigDecimal;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;

import org.mvel2.CompileException;
import org.mvel2.MVEL;
import org.mvel2.PropertyAccessException;


/**
 * 计算工具
 * 
 * @author valsong
 * @date Jul 24, 2017
 *
 */
public class CalculateUtils {

	/**
	 * 根据传入的公式和参数进行计算
	 * 
	 * @param formula
	 * @param variables
	 * @return
	 */
	public static <T> BigDecimal calculate(String formula, Map<String, T> variables) {
		if (SimpleStringUtils.isBlank(formula)) {
			throw new CalculateException("MVEL formula can't be null! formula : " + formula); // 公式不能为空
		}
		if (variables == null || variables.size() == 0) {
			throw new CalculateException("MVEL variables can't be null! variables : " + String.valueOf(variables)); // 参数不能为空
		}
	
		try {
			// 将公式中的变量全部转化为BigDecimal类型
			variables.entrySet().stream().filter(e -> e != null && e.getKey() != null && e.getValue() != null)
					.map(CalculateUtils::convert).collect(Collectors.toMap(Entry::getKey, Entry::getValue));

		} catch (NumberFormatException e) {
			throw new CalculateException(
					"MVEL can't convert to BigDecimal, please check the variables : " + String.valueOf(variables) + "!",
					e);
		} catch (Exception e) {
			throw e;
		}
		BigDecimal result = null;
		try {
			result = (BigDecimal) MVEL.eval(formula, variables);
		} catch (PropertyAccessException pae) {
			throw new CalculateException(
					"MVEL please check the formula :" + formula + " & variables : " + String.valueOf(variables) + "!",
					pae);
		} catch (CompileException ce) {
			throw new CalculateException("MVEL calculate error! ", ce);
		} catch (Exception e) {
			throw e;
		}
		return result;
	}


	/**
	 * 将参数转化为Bigdecimal类型
	 * 
	 * @param entry
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> Entry<String, T> convert(Entry<String, T> entry) {
		if (entry != null) {
			BigDecimal value = null;
			if (entry.getValue() instanceof BigDecimal) {
				value = (BigDecimal) entry.getValue();
			} else {
				value = NumberUtils.getNum(NumberUtils.getNum(entry.getValue()));
			}
			entry.setValue((T) value);
		}
		return entry;
	}

}

异常类


/**
 * 计算异常
 * 
 * @author Val Song
 * @date   Jul 28, 2017
 *
 */
public class CalculateException extends RuntimeException {
	private static final long serialVersionUID = 5162710183389028792L;

	/**
	 * Constructs a {@code CalculateException} with no detail message.
	 */
	public CalculateException() {
		super();
	}

	/**
	 * Constructs a {@code CalculateException} with the specified detail
	 * message.
	 *
	 * @param message
	 *            the detail message.
	 */
	public CalculateException(String message) {
		super(message);
	}

	/**
	 * Constructs a {@code CalculateException} with the specified detail
	 * message & cause
	 * 
	 * @param message
	 * @param cause
	 */
	public CalculateException(String message, Throwable cause) {
		super(message, cause);
	}

}

字符串工具类


/**
 * 字符串工具
 * 
 * @author valsong
 *
 */
public class SimpleStringUtils {

	/**
	 * 判断字符串不为空
	 * 
	 * @param str
	 * @return
	 */
	public static boolean isNotBlank(String str) {
		return !isBlank(str);
	}

	/**
	 * 判断字符串为空
	 * 
	 * @param str
	 * @return
	 */
	public static boolean isBlank(String str) {
		if (str == null || "".equals(str.trim())) {
			return true;
		}
		return false;
	}

	/**
	 *  去首尾空格
	 * 
	 * @param s
	 * @return
	 */
	public static <T> String trim(T s) {
		if (s instanceof String) {
			return s == null ? null : ((String) s).trim();
		} else {
			return s == null ? null : String.valueOf(s).trim();
		}
	}

	/**
	 * 下划线命名转驼峰式
	 * 
	 * @param str
	 * @return
	 */
	public static String toCamel(String str) {
		if (SimpleStringUtils.isBlank(str)) {
			return str;
		}
		StringBuffer buffer = new StringBuffer();
		str = str.toLowerCase().trim();
		char[] charArray = str.toCharArray();
		if (charArray != null) {
			for (int i = 0; i < charArray.length; i++) {
				if ('_' == charArray[i]) {
					i = i + 1;
					buffer.append(Character.toUpperCase(charArray[i]));
				} else {
					buffer.append(charArray[i]);
				}
			}
		}
		return buffer.toString();
	}

	/**
	 * 驼峰转下划线
	 * 
	 * @param str
	 * @return
	 */
	public static String toUnderline(String str) {
		if (SimpleStringUtils.isBlank(str)) {
			return str;
		}
		StringBuffer buffer = new StringBuffer();
		str = str.trim();
		char[] charArray = str.toCharArray();
		if (charArray != null) {
			for (int i = 0; i < charArray.length; i++) {
				if (Character.isUpperCase(charArray[i])) {
					buffer.append("_");
					buffer.append(Character.toLowerCase(charArray[i]));
				} else {
					buffer.append(charArray[i]);
				}
			}
		}
		return buffer.toString();
	}

}


测试类简单粗暴String Double Integer Bigdecimal 都能支持


public class CalculateUtilsTest {

    /**	
     * 20 * 100 - ( 30 -20 ) + 20 ^ 3 + 20/2
     */
    @Test
    public void calculateTest4() {

        String formula = "A * B - (C -D) + E.pow(F) + G / H";

        Map<String, Object> variables = new HashMap<>();
        variables.put("A", "20");
        variables.put("B", 100L);
        variables.put("C", 30.0D);
        variables.put("D", 20);
        variables.put("E", new BigDecimal("20"));
        variables.put("F", "3");
        variables.put("G", "20");
        variables.put("H", "2");

        BigDecimal result = CalculateUtils.calculate(formula, variables);
        Assert.assertTrue(new BigDecimal("10000.0").compareTo(result) == 0);
    }

}

© 著作权归作者所有

共有 人打赏支持
V
粉丝 0
博文 11
码字总数 6686
作品 0
黄浦
程序员
【Java】Fel计算引擎学习

一、前言 最近的项目中,有一个这种需求,系统中配置很多的公式,每个公式中都会有因子。比如:,计算的时候,把这两个因子替换掉,如,,然后通过java来计算出结果。 二、实现的方式 为了解...

kisscatforever ⋅ 05/23 ⋅ 0

Java 编程之美:并发编程高级篇之一

本文来自作者 追梦 在 GitChat 上分享 「Java 编程之美:并发编程高级篇之一」 编辑 | 工藤 前言 借用 Java 并发编程实践中的话:编写正确的程序并不容易,而编写正常的并发程序就更难了。 ...

gitchat ⋅ 05/24 ⋅ 0

【Elasticsearch】打分策略详解与explain手把手计算

一、目的 一个搜索引擎使用的时候必定需要排序这个模块,一般情况下在不选择按照某一字段排序的情况下,都是按照打分的高低进行一个默认排序的,所以如果正式使用的话,必须对默认排序的打分...

Airship ⋅ 05/10 ⋅ 0

从Java到JVM到OS线程的优先级

前言 Java 的线程的调度机制由 JVM 实现,假如有若干条线程,你想让某些线程拥有更长的执行时间,或某些线程分配少点执行时间,这时就涉及“线程优先级”。 优先级别 Java 把线程优先级分成1...

超人汪小建 ⋅ 昨天 ⋅ 0

MySQL多数据源笔记5-ShardingJDBC实战

Sharding-JDBC集分库分表、读写分离、分布式主键、柔性事务和数据治理与一身,提供一站式的解决分布式关系型数据库的解决方案。 从2.x版本开始,Sharding-JDBC正式将包名、Maven坐标、码云仓...

狂小白 ⋅ 03/19 ⋅ 0

如何计算Java对象所占内存的大小

摘要 本文以如何计算Java对象占用内存大小为切入点,在讨论计算Java对象占用堆内存大小的方法的基础上,详细讨论了Java对象头格式并结合JDK源码对对象头中的协议字段做了介绍,涉及内存模型、...

阿里云云栖社区 ⋅ 05/24 ⋅ 0

深入理解Java虚拟机的体系结构

JAVA虚拟机的生命周期 一个运行时的Java虚拟机实例的天职是:负责运行一个java程序。当启动一个Java程序时,一个虚拟机实例也就诞生了。当该程序关闭退出,这个虚拟机实例也就随之消亡。如果...

java进阶 ⋅ 06/22 ⋅ 0

sharding-jdbc源码分析—准备工作

原文作者:阿飞Javaer 原文链接:https://www.jianshu.com/p/7831817c1da8 接下来对sharding-jdbc源码的分析基于tag为源码,根据sharding-jdbc Features深入学习sharding-jdbc的几个主要特性...

飞哥-Javaer ⋅ 05/03 ⋅ 0

ThreadLocal源码分析

阅读原文请访问我的博客 BrightLoong's Blog 一. 简介 提醒篇幅较大需耐心。 简介来自ThreadLocal类注释 ThreadLocal类提供了线程局部 (thread-local) 变量。这些变量与普通变量不同,每个线...

BrightLoong ⋅ 05/28 ⋅ 0

sharding-jdbc分库分表规则(1)-单表查询

前言 当数据量到达一定数量级的时候,一般都会考虑分库分表。sharding-jdbc是一个开源的客户端分库分表基础类库,以一个jar包的形式提供,基于原生的JDBC驱动进行增强,基本能够无缝整合旧代...

xiaomin0322 ⋅ 06/07 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

tcp/ip详解-链路层

简介 设计链路层的目的: 为IP模块发送和接收IP数据报 为ARP模块发送ARP请求和接收ARP应答 为RARP模块发送RARP请求和接收RARP应答 TCP/IP支持多种链路层协议,如以太网、令牌环往、FDDI、RS-...

loda0128 ⋅ 今天 ⋅ 0

spring.net aop代码例子

https://www.cnblogs.com/haogj/archive/2011/10/12/2207916.html

whoisliang ⋅ 今天 ⋅ 0

发送短信如何限制1小时内最多发送11条短信

发送短信如何限制1小时内最多发送11条短信 场景: 发送短信属于付费业务,有时为了防止短信攻击,需要限制发送短信的频率,例如在1个小时之内最多发送11条短信. 如何实现呢? 思路有两个 截至到当...

黄威 ⋅ 昨天 ⋅ 0

mysql5.7系列修改root默认密码

操作系统为centos7 64 1、修改 /etc/my.cnf,在 [mysqld] 小节下添加一行:skip-grant-tables=1 这一行配置让 mysqld 启动时不对密码进行验证 2、重启 mysqld 服务:systemctl restart mysql...

sskill ⋅ 昨天 ⋅ 0

Intellij IDEA神器常用技巧六-Debug详解

在调试代码的时候,你的项目得debug模式启动,也就是点那个绿色的甲虫启动服务器,然后,就可以在代码里面断点调试啦。下面不要在意,这个快捷键具体是啥,因为,这个keymap是可以自己配置的...

Mkeeper ⋅ 昨天 ⋅ 0

zip压缩工具、tar打包、打包并压缩

zip 支持压缩目录 1.在/tmp/目录下创建目录(study_zip)及文件 root@yolks1 study_zip]# !treetree 11└── 2 └── 3 └── test_zip.txt2 directories, 1 file 2.yum...

蛋黄Yolks ⋅ 昨天 ⋅ 0

聊聊HystrixThreadPool

序 本文主要研究一下HystrixThreadPool HystrixThreadPool hystrix-core-1.5.12-sources.jar!/com/netflix/hystrix/HystrixThreadPool.java /** * ThreadPool used to executed {@link Hys......

go4it ⋅ 昨天 ⋅ 0

容器之上传镜像到Docker hub

Docker hub在国内可以访问,首先要创建一个账号,这个后面会用到,我是用126邮箱注册的。 1. docker login List-1 Username不能使用你注册的邮箱,要用使用注册时用的username;要输入密码 ...

汉斯-冯-拉特 ⋅ 昨天 ⋅ 0

SpringBoot简单使用ehcache

1,SpringBoot版本 2.0.3.RELEASE ①,pom.xml <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.0.3.RELE......

暗中观察 ⋅ 昨天 ⋅ 0

Spring源码解析(八)——实例创建(下)

前言 来到实例创建的最后一节,前面已经将一个实例通过不同方式(工厂方法、构造器注入、默认构造器)给创建出来了,下面我们要对创建出来的实例进行一些“加工”处理。 源码解读 回顾下之前...

MarvelCode ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部