震惊,竟然能通过表达式计算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,打完手工,如果觉得文章不错,还请各位给俺一键三连吧!!!

相关内容

热门资讯

AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWR报告解读 WORKLOAD REPOSITORY PDB report (PDB snapshots) AW...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
群晖外网访问终极解决方法:IP... 写在前面的话 受够了群晖的quickconnet的小水管了,急需一个新的解决方法&#x...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
Azure构建流程(Power... 这可能是由于配置错误导致的问题。请检查构建流程任务中的“发布构建制品”步骤,确保正确配置了“Arti...