震惊,竟然能通过表达式计算VO,再也不用手打Getter计算方法了,程序员福利
创始人
2025-05-29 03:02:43
0次

我有一个问题:

假设我们从给前端返回一个VO,但是VO中的某些属性需要通过计算得来的。如果我们每次都要在实体类中直接计算的话,不利于代码维护性,每次改变计算方法都要重新修改方法,十分麻烦。所以我就想能不能通过一个数学表达式来计算实体类中的属性,这样的话我每次更改计算方法的话,我只需要修改表达式就可以了。说干就干,今天它来了

细微琢磨一下:

引入pom

  org.codehaus.groovygroovy
  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,打完手工,如果觉得文章不错,还请各位给俺一键三连吧!!!

相关内容

热门资讯

前端-session、jwt 目录:   (1)session (2&#x...
linux入门---制作进度条 了解缓冲区 我们首先来看看下面的操作: 我们首先创建了一个文件并在这个文件里面添加了...
关于测试,我发现了哪些新大陆 关于测试 平常也只是听说过一些关于测试的术语,但并没有使用过测试工具。偶然看到编程老师...
前缀和与对数器与二分法 1. 前缀和 假设有一个数组,我们想大量频繁的去访问L到R这个区间的和,...
nodejs:本地安装nvm实... 一、背景-使用不同版本node的原因 vue3+ts、nuxt3版本,node...
JAVA集合知识整理 Java集合知识整理 HashMap相关 HashMap的底层数据结构:jdk1.8之...
无刷直流电机介绍及单片机控制实... 无刷直流电机介绍及单片机控制实例前言基本概念优势与劣势使用寿命基本结构使用单片机控制实例电子调速器&...
fwdiary(2) dp2 1.传纸条  AcWing 275. 传纸条 - AcWing 走两条路,走一条最大的...
常用的DOS命令 常用的DOS命令 DOS(Disk Operating System,磁...
<C++> 类和对象(下) 1.const成员函数将const修饰的“成员函数”称之为const成员函数,cons...