假设我们从给前端返回一个VO,但是VO中的某些属性需要通过计算得来的。如果我们每次都要在实体类中直接计算的话,不利于代码维护性,每次改变计算方法都要重新修改方法,十分麻烦。所以我就想能不能通过一个数学表达式来计算实体类中的属性,这样的话我每次更改计算方法的话,我只需要修改表达式就可以了。说干就干,今天它来了
引入pom
org.codehaus.groovy groovy
public static void main(String args[]) {Binding binding = new Binding();binding.setVariable("F",2.5);binding.setVariable("T",30);binding.setVariable("A",100);binding.setVariable("P0",100);binding.setVariable("language", "Groovy");GroovyShell shell = new GroovyShell(binding);Object F1 =shell.evaluate("P1=(F+T); return P1 ");Object F2 =shell.evaluate("P1=P0*(0.055*0.20+1.0011)+A; return P1 ");System.out.println(F1);System.out.println(F2);}
产生了一个新的问题,我不可能我手动输入这些实体类中的Key吧,这也太累了吧,然后我就想到了可以通过反射方法,取到实体类中的Key还有value,然后给塞到Binding
类中。然后说干就干封装工具类。
import groovy.lang.Binding;
import lombok.SneakyThrows;
import org.springframework.beans.BeanUtils;
import org.springframework.util.ReflectionUtils;import java.lang.reflect.Field;public class BindingUtils {/*** 设置给定变量的值* 反射出给定对象的属性,依次遍历属性并逐个调用Binding.setVariable(String name,Object value)方法。* 成功后结果集模型如下:* Binding binding = new Binding();* binding.setVariable("F",2.5);* binding.setVariable("T",30);* binding.setVariable("A",100);* binding.setVariable("P0",100);** @param object 给定变量值* @return groovy.lang.Binding* @author 陈俐润* @since 2023/3/13*/@SneakyThrowspublic static Binding setVariableObject(T source) {Object object = source.getClass().newInstance();BeanUtils.copyProperties(source, object);Binding binding = new Binding();// 遍历出实体类中全部字段Field[] declaredFields = object.getClass().getDeclaredFields();for (Field declaredField : declaredFields) {String propertyName = declaredField.getName();//抑制java语言访问检查,反射访问private访问权限的属性值declaredField.setAccessible(true);// 获取实体类中属性的值Object value = ReflectionUtils.getField(declaredField, object);// 将获取的属性名和值赋值给Binding方法中binding.setVariable(propertyName, value);}return binding;}
}
这么说来那我表达式也不能在代码中写吧,我应该从数据库中取出来然后计算,然后就有了下面的工具类,用来取到表达式+计算为一体的工具类,十分贴心。
import groovy.lang.Binding;
import groovy.lang.GroovyShell;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ReflectionUtils;import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.List;@Slf4j
public class OfficeUtils {/*** 根据表达式填充报表数据* 返回计算后的结果集合** @param dataList 需要被填充的报表数据集合* @param exprList 声明表达式对象* @return java.util.List 返回填充完成后的数据结果* @author 陈俐润* @since 2023/3/13*/public static List getOfficeResultList(List dataList, List exprList) {dataList.forEach(data -> getOfficeResultImpl(data, exprList));return dataList;}/*** 根据表达式填充报表数据* 返回计算后的结果** @param data 需要被填充的报表数据* @param exprList 声明表达式对象* @return java.util.List 返回填充完成后的数据结果* @author 陈俐润* @since 2023/3/13*/public static void getOfficeResult(K data, List exprList) {getOfficeResultImpl(data, exprList);}@SneakyThrowsprivate static void getOfficeResultImpl(K data, List exprList) {Binding binding = BindingUtils.setVariableObject(data);GroovyShell groovyShell = new GroovyShell(binding);exprList.forEach(expr -> {// 获取列charCode值Field charCodeField = ReflectionUtils.findField(expr.getClass(), "charCode");charCodeField.setAccessible(true);String charCodeValue = (String) ReflectionUtils.getField(charCodeField, expr);// 获取列expr值Field exprField = ReflectionUtils.findField(expr.getClass(), "expr");exprField.setAccessible(true);String exprValue = (String) ReflectionUtils.getField(exprField, expr);log.debug("公式:{}", exprValue);BigDecimal evaluate = (BigDecimal) groovyShell.evaluate(exprValue);// 给数据模型指定字段赋值Field dataField = ReflectionUtils.findField(data.getClass(), charCodeValue);dataField.setAccessible(true);ReflectionUtils.setField(dataField, data, evaluate);});}
}
这里我听给解释一下源码,charCode
代表需要给VO中计算的结果字段,例如:age
就是结果字段,我需要给age
赋值,这时候我这个charCode
就是age,expr 字段就是表达式了,例如 age= 1+1
;在一个就是表达式Bean模型中要有这两个字段哦。
1、两个基本实体类,要计算的属性一定是BigDecimal
类型的,不然会报错!!!
基本VO类
@Data
@AllArgsConstructor
@NoArgsConstructor
class Woman{private BigDecimal a;private BigDecimal b;private BigDecimal c;
}
基本的表达式Bean
@Data
@AllArgsConstructor
@NoArgsConstructor
class Expr{private String charCode;private String expr;
}
2、赋值,测试,一竿子插到底
public static void main(String[] args) {Woman woman = new Woman();woman.setA(BigDecimal.valueOf(1));woman.setB(BigDecimal.valueOf(1));List exprs = new ArrayList<>();exprs.add(new Expr("c","c=a+10;return c"));OfficeUtils.getOfficeResult(woman,exprs);System.out.println(woman.getC());}
OK,打完手工,如果觉得文章不错,还请各位给俺一键三连吧!!!