始终会用上的Common BeanUtils(转载)_javabeanNo .01

 

Beanutils用了魔术般的反射技术,实现了很多夸张有用的功能,都是C/C++时代不敢想的。无论谁的项目,始终一天都会用得上它。我算是后知后觉了,第一回看到它的时候居然错过。

1.属性的动态getter、setter

在这框架满天飞的年代,不能事事都保证执行getter,setter函数了,有时候属性是要根据名字动态取得的,就像这样:  
BeanUtils.getProperty(myBean,"code");
而Common BeanUtils的更强功能在于可以直接访问内嵌对象的属性,只要使用点号分隔。
BeanUtils.getProperty(orderBean, "address.city");
相比之下其他类库的BeanUtils通常都很简单,不能访问内嵌的对象,所以有时要用Commons BeanUtils来替换它们。

BeanUtils还支持List和Map类型的属性,如下面的语法即可取得Order的顾客列表中第一个顾客的名字
BeanUtils.getProperty(orderBean, "customers[1].name");
其中BeanUtils会使用ConvertUtils类把字符串转为Bean属性的真正类型,方便从HttpServletRequest等对象中提取bean,或者把bean输出到页面。
而PropertyUtils就会原色的保留Bean原来的类型。

2.BeanCompartor 动态排序

还是通过反射,动态设定Bean按照哪个属性来排序,而不再需要在实现bean的Compare接口进行复杂的条件判断。
List peoples = ...; // Person对象的列表
Collections.sort(peoples, new BeanComparator("age"));

如果要支持多个属性的复合排序,如"Order By lastName,firstName"

ArrayList sortFields = new ArrayList();
sortFields.add(new BeanComparator("lastName"));
sortFields.add(new BeanComparator("firstName"));
ComparatorChain multiSort = new ComparatorChain(sortFields);
Collections.sort(rows,multiSort);

其中ComparatorChain属于jakata commons-collections包。
如果age属性不是普通类型,构造函数需要再传入一个comparator对象为age变量排序。
另外, BeanCompartor本身的ComparebleComparator, 遇到属性为null就会抛出异常, 也不能设定升序还是降序。这个时候又要借助commons-collections包的ComparatorUtils.

   Comparator mycmp = ComparableComparator.getInstance();
   mycmp = ComparatorUtils.nullLowComparator(mycmp);  //允许null
   mycmp = ComparatorUtils.reversedComparator(mycmp); //逆序
   Comparator cmp = new BeanComparator(sortColumn, mycmp);
3.Converter 把Request或ResultSet中的字符串绑定到对象的属性

   经常要从request,resultSet等对象取出值来赋入bean中,如果不用MVC框架的绑定功能的话,下面的代码谁都写腻了。

   String a = request.getParameter("a");
bean.setA(a);
String b = ....
bean.setB(b);
......

不妨写一个Binder自动绑定所有属性:

    MyBean bean = ...;
HashMap map = new HashMap();
Enumeration names = request.getParameterNames();
while (names.hasMoreElements())
{
String name = (String) names.nextElement();
map.put(name, request.getParameterValues(name));
}
BeanUtils.populate(bean, map);

    其中BeanUtils的populate方法或者getProperty,setProperty方法其实都会调用convert进行转换。
    但 Converter只支持一些基本的类型,甚至连java.util.Date类型也不支持。而且它比较笨的一个地方是当遇到不认识的类型时,居然会抛出 异常来。 对于Date类型,我参考它的sqldate类型实现了一个Converter,而且添加了一个设置日期格式的函数。
要把这个Converter注册,需要如下语句:

    ConvertUtilsBean convertUtils = new ConvertUtilsBean();
   DateConverter dateConverter = new DateConverter();
   convertUtils.register(dateConverter,Date.class);



//因为要注册converter,所以不能再使用BeanUtils的静态方法了,必须创建BeanUtilsBean实例
BeanUtilsBean beanUtils = new BeanUtilsBean(convertUtils,new PropertyUtilsBean());
beanUtils.setProperty(bean, name, value);
4 其他功能
4.1 ConstructorUtils,动态创建对象
     public static Object invokeConstructor(Class klass, Object arg)
4.2 MethodUtils,动态调用方法
    MethodUtils.invokeMethod(bean, methodName, parameter);

4.3 PropertyUtils,当属性为Collection,Map时的动态读取:
Collection: 提供index
   BeanUtils.getIndexedProperty(orderBean,"items",1);
或者
  BeanUtils.getIndexedProperty(orderBean,"items[1]");
Map: 提供Key Value
  BeanUtils.getMappedProperty(orderBean, "items","111");//key-value goods_no=111 
或者
  BeanUtils.getMappedProperty(orderBean, "items(111)") 

4.4 PropertyUtils,直接获取属性的Class类型
     public static Class getPropertyType(Object bean, String name)
if (total1.compareTo(total2) > 0) { List<PpMachiningOrderList> _group = new ArrayList<>(); List<PpMachiningOrderList> nextList = new ArrayList<>(); PpMachiningOrderList order = group1.get(0); String ct = order.getCt(); String oee = order.getOee(); BigDecimal manualQty = order.getManualQty(); if (minGroup != null) { ct = minGroup.getCt(); oee = minGroup.getOee(); manualQty = minGroup.getManualQty(); } for (PpMachiningOrderList _order : group1) { BigDecimal qty = _order.getAddQty(); if (total2.compareTo(BigDecimal.ZERO) <= 0) { nextList.add(_order); } else { if (qty.compareTo(total2) < 0) { _order.setTotalTime(qty.multiply(new BigDecimal(ct)).divide(new BigDecimal(oee), 6, RoundingMode.DOWN)); _order.setCt(ct); _order.setOee(oee); _order.setManualQty(manualQty); _group.add(_order); total2 = total2.subtract(qty); } else if (qty.compareTo(total2) > 0) { // 拆分出的任务用物料自己的CT、OEE计算工时 // 多出来的部分给下一组 BigDecimal subNextQty = qty.subtract(total2); _order.setTotalTime(total2.multiply(new BigDecimal(ct)).divide(new BigDecimal(oee), 6, RoundingMode.DOWN)); _order.setCt(ct); _order.setOee(oee); _order.setManualQty(manualQty); // _order.setQty(total2); _order.setAddQty(total2); _group.add(_order); PpMachiningOrderList newOrder = new PpMachiningOrderList(); BeanUtils.copyProperties(_order, newOrder); // newOrder.setQty(subNextQty); newOrder.setAddQty(subNextQty); newOrder.setTotalTime(subNextQty.multiply(new BigDecimal(ct)).divide(new BigDecimal(oee), 6, RoundingMode.DOWN)); nextList.add(newOrder); total2 = BigDecimal.ZERO; } else { _group.add(_order); } } } group1.clear(); group1.addAll(_group); insertQueue.add(nextList); } else if (total1.compareTo(total2) < 0) { List<PpMachiningOrderList> _group = new ArrayList<>(); List<PpMachiningOrderList> nextList = new ArrayList<>(); PpMachiningOrderList order = group2.get(0); String ct = order.getCt(); String oee = order.getOee(); BigDecimal manualQty = order.getManualQty(); if (minGroup != null) { ct = minGroup.getCt(); oee = minGroup.getOee(); manualQty = minGroup.getManualQty(); } for (PpMachiningOrderList _order : group2) { BigDecimal qty = _order.getAddQty(); if (total1.compareTo(BigDecimal.ZERO) <= 0) { nextList.add(_order); } else { if (qty.compareTo(total1) < 0) { _order.setTotalTime(qty.multiply(new BigDecimal(ct)).divide(new BigDecimal(oee), 6, RoundingMode.DOWN)); _order.setCt(ct); _order.setOee(oee); _order.setManualQty(manualQty); _group.add(_order); total1 = total1.subtract(qty); } else if (qty.compareTo(total1) > 0) { // 拆分出的任务用物料自己的CT、OEE计算工时 // 多出来的部分给下一组 BigDecimal subNextQty = qty.subtract(total1); _order.setTotalTime(total1.multiply(new BigDecimal(ct)).divide(new BigDecimal(oee), 6, RoundingMode.DOWN)); _order.setCt(ct); _order.setOee(oee); _order.setManualQty(manualQty); // _order.setQty(total1); _order.setAddQty(total1); _group.add(_order); PpMachiningOrderList newOrder = new PpMachiningOrderList(); BeanUtils.copyProperties(_order, newOrder); // newOrder.setQty(subNextQty); newOrder.setAddQty(subNextQty); newOrder.setTotalTime(subNextQty.multiply(new BigDecimal(ct)).divide(new BigDecimal(oee), 6, RoundingMode.DOWN)); nextList.add(newOrder); total1 = BigDecimal.ZERO; } else { _group.add(_order); } } } group2.clear(); group2.addAll(_group); insertQueue.add(nextList); } newOrder.setTotalTime(subNextQty.multiply(new BigDecimal(ct)).divide(new BigDecimal(oee), 6, RoundingMode.DOWN)); 这里用的ct和oee应该是他原本的值, 而不是if (minGroup != null) { ct = minGroup.getCt(); oee = minGroup.getOee(); manualQty = minGroup.getManualQty(); }之后的
最新发布
11-04
你提出的问题非常关键,涉及到一个 **逻辑错误或语义歧义**:在拆分订单(`PpMachiningOrderList`)时,新生成的 `newOrder` 的工时(`totalTime`)计算应该使用 **原始物料自身的 CT 和 OEE**,而不是被 `minGroup` 覆盖后的统一值。 而当前代码中: ```java newOrder.setTotalTime(subNextQty.multiply(new BigDecimal(ct)).divide(new BigDecimal(oee), 6, RoundingMode.DOWN)); ``` 使用的 `ct` 和 `oee` 是可能已经被 `minGroup` 修改过的值(即全局最小组的标准),这会导致 **后续拆分出的任务用错了 CT/OEE 来计算工时** —— 违背了注释中的说明:“拆分出的任务用物料自己的CT、OEE计算工时”。 --- ### ✅ 正确做法: 你应该 **保留原始订单的 CT 和 OEE**,用于计算拆分后“下一批”任务的工时。也就是说,在进入循环前不要让 `ct`, `oee`, `manualQty` 被 `minGroup` 覆盖影响到个体拆分逻辑。 --- ## ✅ 解决方案与重构建议 我们可以通过以下方式修正这个问题: ### ✔️ 方案一:只对 `_group` 中合并部分使用 `minGroup` 的参数;对 `nextList` 拆分部分仍使用原对象自己的 `ct`/`oee` 修改思路: - 合并进当前批次(_group)的任务:使用 `minGroup` 的标准 CT/OEE(统一化处理) - 拆分出去给下一组的任务(nextList):保持其 **原有 CT/OEE** 下面是修复后的完整代码(以 `total1.compareTo(total2) > 0` 分支为例): ```java if (total1.compareTo(total2) > 0) { List<PpMachiningOrderList> _group = new ArrayList<>(); List<PpMachiningOrderList> nextList = new ArrayList<>(); // 当前组 group1 使用 minGroup 的 CT/OEE 做统一化处理 PpMachiningOrderList order = group1.get(0); String ct = order.getCt(); String oee = order.getOee(); BigDecimal manualQty = order.getManualQty(); if (minGroup != null) { ct = minGroup.getCt(); oee = minGroup.getOee(); manualQty = minGroup.getManualQty(); } for (PpMachiningOrderList _order : group1) { BigDecimal qty = _order.getAddQty(); if (total2.compareTo(BigDecimal.ZERO) <= 0) { // 所有剩余直接放入 nextList,使用自己原来的 CT/OEE nextList.add(_order); } else { if (qty.compareTo(total2) < 0) { // 全部纳入当前组,使用 minGroup 标准 _order.setTotalTime(qty.multiply(new BigDecimal(ct)).divide(new BigDecimal(oee), 6, RoundingMode.DOWN)); _order.setCt(ct); _order.setOee(oee); _order.setManualQty(manualQty); _group.add(_order); total2 = total2.subtract(qty); } else if (qty.compareTo(total2) > 0) { // 拆分:当前部分使用 minGroup 的 CT/OEE _order.setTotalTime(total2.multiply(new BigDecimal(ct)).divide(new BigDecimal(oee), 6, RoundingMode.DOWN)); _order.setCt(ct); _order.setOee(oee); _order.setManualQty(manualQty); _order.setAddQty(total2); _group.add(_order); // 下一组部分:新建对象,使用原订单自己的 CT/OEE 计算工时 PpMachiningOrderList newOrder = new PpMachiningOrderList(); BeanUtils.copyProperties(_order, newOrder); BigDecimal subNextQty = qty.subtract(total2); // 关键修复点:这里使用原订单的 CT 和 OEE,而非 minGroup 的 newOrder.setAddQty(subNextQty); newOrder.setTotalTime( subNextQty .multiply(new BigDecimal(_order.getCt())) // ← 原始 CT .divide(new BigDecimal(_order.getOee()), 6, RoundingMode.DOWN) // ← 原始 OEE ); // 注意:不覆盖 newOrder 的 ct/oee/manualQty,保持原始值 nextList.add(newOrder); total2 = BigDecimal.ZERO; } else { // qty == total2,刚好匹配 _order.setTotalTime(qty.multiply(new BigDecimal(ct)).divide(new BigDecimal(oee), 6, RoundingMode.DOWN)); _order.setCt(ct); _order.setOee(oee); _order.setManualQty(manualQty); _group.add(_order); total2 = BigDecimal.ZERO; } } } group1.clear(); group1.addAll(_group); insertQueue.add(nextList); } ``` > ⚠️ 对 `total1.compareTo(total2) < 0` 的分支也需要做同样修改,替换 `group2` 相关逻辑,并确保 `newOrder` 使用的是 `_order.getCt()` 和 `_order.getOee()`。 --- ### 🔍 为什么这样做是正确的? | 场景 | 应该使用的 CT/OEE | 理由 | |------|------------------|------| | 当前组加工任务(已分配完产能) | `minGroup` 的 CT/OEE | 统一按效率最高的标准排程 | | 拆分后留给下一轮的任务 | 原始订单自己的 CT/OEE | 尚未参与统一优化,保留原始工艺参数 | 这也符合你的注释描述: > “拆分出的任务用物料自己的CT、OEE计算工时” --- ### 🛠 工具建议:封装 getTime(BigDecimal qty, String ct, String oee) 为了减少重复代码,可以提取工具方法: ```java private BigDecimal calculateTime(BigDecimal qty, String ct, String oee) { return qty.multiply(new BigDecimal(ct)) .divide(new BigDecimal(oee), 6, RoundingMode.DOWN); } ``` 然后替换所有类似表达式为: ```java _order.setTotalTime(calculateTime(total2, ct, oee)); // vs newOrder.setTotalTime(calculateTime(subNextQty, _order.getCt(), _order.getOee())); ``` 更清晰地区分不同来源的参数。 --- ### ✅ 总结修复要点 1. **问题本质**:`newOrder` 错误地使用了 `minGroup` 覆盖后的 `ct`/`oee`。 2. **正确行为**:拆分出去的部分应使用原始订单的 `ct` 和 `oee`。 3. **解决方案**:在创建 `newOrder` 时,调用 `_order.getCt()` 和 `_order.getOee()` 来计算 `totalTime`。 4. **扩展建议**:将时间计算抽象成函数,避免硬编码。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值