概述
之前给公司的供应链同事开发了一个通过管理后台下单的功能,他们会把订单数据放到excel里,然后导入到管理后台,就能给门店下单了。
但是当时上线时,没有做校验excel里是否有重复记录的功能,导致一不小心,就会重复下单。
使用JAVA的分组功能校验重复数据
由于给门店下单的数量不多,一般不会超过500单,因此不需要分批处理,就直接一次性处理即可。
那么怎样算是重复的订单?
门店 + 物料 + 到货日期
只要这三个字段是一样的记录,就认为是重复的,必须提醒操作人,excel有重复记录。
在JAVA的List里,如果想对List里的对象的【多个字段 】进行分组,可以采用Function
来自定义一个组合键:
java
Function<Order, String> compositeKey = order -> String.format("%s_%s",
order.getShopName(),order.getMaterialName(),order.getArrivalDay());
定义好这个组合键后,就可以传入到Collectors.groupingBy()
方法里,让List按照组合键进行分组。
java
Map<String, Long> groupByOrderKeyMap = orderList.stream().collect(Collectors.groupingBy(compositeKey,Collectors.counting()));
一旦有重复的记录,就抛出异常,提示操作人记录重复了。
java
groupByOrderKeyMap.entrySet().stream()
.filter(entry -> entry.getValue() > 1)
.findFirst()
.ifPresent(entry -> {
String [] keyArray = entry.getKey().split("_");
String msg = "表格里有重复记录:"+keyArray[0]+","+keyArray[1];
throw new RuntimeException(msg);
});
更优雅的方式
上面的代码里,是使用String.format()
方法,将对象的多个字段拼接起来,作为组合key的,这样在解析组合key的时候,就需要使用split()
方法进行切割,不太优雅。
其实可以在Order对象里创建一个构造方法,传入门店、物料以及到货日期,然后把整个对象作为组合key的。
java
@Data
public class Order {
private String arrivalDay;
private String materialName;
private String shopName;
public Order(String shopName, String materialName, String arrivalDay) {
this.arrivalDay = arrivalDay;
this.materialName = materialName;
this.shopName = shopName;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Order order = (Order) o;
return Objects.equals(arrivalDay, order.arrivalDay) &&
Objects.equals(materialName, order.materialName) &&
Objects.equals(shopName, order.shopName);
}
@Override
public int hashCode() {
return Objects.hash(arrivalDay, materialName, shopName);
}
}
重写equals
和hashCode
方法后,就可以使用如下代码进行分组了。
java
Map<Order, Long> groupByOrderKeyMap = orders.stream()
.collect(Collectors.groupingBy(o -> new Order(o.getShopName(), o.getMaterialName(), o.getArrivalDay()),Collectors.counting()));
这样获取组合key的时候,拿到就是一个Order对象,可以非常方便的获取到对象的字段值。
java
groupByOrderKeyMap.entrySet().stream()
.filter(entry -> entry.getValue() > 1)
.findFirst()
.ifPresent(entry -> {
String msg = "表格里有重复记录:"+entry.getShopName()+","+entry.getMaterialName();
throw new RuntimeException(msg);
});
如果想把所有重复的记录都找出来,怎么做?
上面的代码是,只要有一条记录出现重复了,就立刻抛出异常。操作人处理完后,可能还有重复记录他不知道,就又得处理一次甚至多次。
最好能一次性告知操作人,excel里有哪些记录重复了,这样操作人就可以一次性处理掉。代码如下:
java
Function<Order, String> compositeKey = order -> String.format("%s_%s",
order.getShopName(),order.getMaterialName(),order.getArrivalDay());
Map<String, List<Order> groupByOrderKeyMap = orderList.stream().collect(Collectors.groupingBy(compositeKey,Collectors.toList()));
输出所有重复的记录
java
groupByOrderKeyMap.values().stream()
.filter(list -> list.size() > 1)
.forEach(duplicates -> {
duplicates.forEach(order -> System.out.println(order));
});