场景:使用审计日志 对角色权限进行修改信息的记录,将数据封装进对应的填充信息,由于会使用到userModify,针对用户批量修改 添加、删除角色,这时候就需要 先做删除逻辑判断出 角色信息,再坐新增逻辑 添加对应角色。 整理一下,会出现以下情况,多个人员 Person 有不同工号,需要修改 可能相同的角色 也可能不同, 删除 可能相同 也可能不同的角色。
举例:存在 人员Byron:A B C roleCode需要删除 新增BA的roleCode PesronId 1
test 删除 A roleCode PersonId 2
Ftest 新增 voidF PersonId 3
AuditLogUserRoleTO A = new AuditLogUserRoleTO();
AuditLogUserRoleTO B = new AuditLogUserRoleTO();
AuditLogUserRoleTO C = new AuditLogUserRoleTO();
AuditLogUserRoleTO D = new AuditLogUserRoleTO();
AuditLogUserRoleTO F = new AuditLogUserRoleTO();
AuditLogUserRoleTO BA = new AuditLogUserRoleTO();
A.setDeleteRole("A");
A.setUserName("Byron");
A.setPersonId("1");
BeanUtils.copyProperties(A,B);
B.setDeleteRole("B");
BeanUtils.copyProperties(A,C);
C.setDeleteRole("C");
BeanUtils.copyProperties(A,D);
D.setUserName("test");
D.setPersonId("2");
BA.setAddRole("BA");
BA.setUserName("Byron");
BA.setPersonId("1");
F.setAddRole("voidF");
F.setUserName("Ftest");
F.setPersonId("3");
根据当前的人员信息 汇总出一套 需要删除的 LIst<> deleteData 集合 和 List<> addData集合
List<AuditLogUserRoleTO> deleteData = new ArrayList<AuditLogUserRoleTO>();
List<AuditLogUserRoleTO> addData = new ArrayList<AuditLogUserRoleTO>();
deleteData.add(A);
deleteData.add(B);
deleteData.add(C);
deleteData.add(D);
addData.add(BA);
addData.add(F);
System.out.println(deleteData);
System.out.println(addData);
deleteData:
[AuditLogUserRoleTO(userName=Byron, personId=1, deleteRole=A, addRole=null), AuditLogUserRoleTO(userName=Byron, personId=1, deleteRole=B, addRole=null), AuditLogUserRoleTO(userName=Byron, personId=1, deleteRole=C, addRole=null), AuditLogUserRoleTO(userName=test, personId=2, deleteRole=A, addRole=null)]
addData:
[AuditLogUserRoleTO(userName=Byron, personId=1, deleteRole=null, addRole=BA), AuditLogUserRoleTO(userName=Ftest, personId=3, deleteRole=null, addRole=voidF)]
去重逻辑开始
根据新增角色,对删除角色去重,以人员UserName为标准,并返回List<>集合
List<AuditLogUserRoleTO> list = addData.stream().
filter(
e -> !deleteData.stream().map(AuditLogUserRoleTO::getUserName).collect(Collectors.toList())
.contains(e.getUserName()))
.collect(Collectors.toList());
System.out.println(list);
List<>返回信息:由于根据UserName求差集,add:Byron Ftest 针对delete:Byron test 求差集得到Ftest
[AuditLogUserRoleTO(userName=Ftest, personId=3, deleteRole=null, addRole=voidF)]
由于数据此时是割裂的状态,需要将数据根据人员进行汇总成,删除、新增roleCode同时存在的信息
对deleteData遍历,更具UserName添加addRole
List<AuditLogUserRoleTO> data = new ArrayList<>();
for (AuditLogUserRoleTO delete : deleteData){
for (AuditLogUserRoleTO add : addData){
if (delete.getUserName().equals(add.getUserName())){
delete.setAddRole(add.getAddRole());
}
}
}
汇总添加到deleteData的List中,因为最终是要形成审计信息的对象,将这个List<>丢进data中。
deleteData.addAll(list);
System.out.println("deleteData:++++:"+deleteData);
data.addAll(deleteData);
System.out.println(data);
List<AuditLogUserRoleTO> tempList = new ArrayList<>();
此时汇总的deleteData 既携带了addRole 也携带了deleteRole,完整信息,存在重复,需要二次处理
deleteData:++++:
[AuditLogUserRoleTO(userName=Byron, personId=1, deleteRole=A, addRole=BA), AuditLogUserRoleTO(userName=Byron, personId=1, deleteRole=B, addRole=BA), AuditLogUserRoleTO(userName=Byron, personId=1, deleteRole=C, addRole=BA), AuditLogUserRoleTO(userName=test, personId=2, deleteRole=A, addRole=null), AuditLogUserRoleTO(userName=Ftest, personId=3, deleteRole=null, addRole=voidF)]
把信息添加到最终发往记录信息用的data中:
data:
[AuditLogUserRoleTO(userName=Byron, personId=1, deleteRole=A, addRole=BA), AuditLogUserRoleTO(userName=Byron, personId=1, deleteRole=B, addRole=BA), AuditLogUserRoleTO(userName=Byron, personId=1, deleteRole=C, addRole=BA), AuditLogUserRoleTO(userName=test, personId=2, deleteRole=A, addRole=null), AuditLogUserRoleTO(userName=Ftest, personId=3, deleteRole=null, addRole=voidF)]
这里穿件了一个tempList是为了防止对原数据处理引起不必要的麻烦,用一个临时信息作为真正需要计入审计信息的内容
对这时候的data遍历,获取人员UserName,并且将对应的角色放进sb1,sb2的HashSet中,这里采用HashSet的原因是:原来使用StringBuilder,会把遍历过程中重复出现的新增或删除roleCode,不断拼接添加进去,这样最终打印显示会出现重复。HashSet本身可以进行去重,解决该问题。
//StringBuilder sb1 = new StringBuilder();
//StringBuilder sb2 = new StringBuilder();
if (CollectionUtils.isEmpty(data)){
return;
}
for (AuditLogUserRoleTO audit : data){
HashSet sb1 = new HashSet();
HashSet sb2 = new HashSet();
AuditLogUserRoleTO temp = new AuditLogUserRoleTO();
temp.setUserName(audit.getUserName());
for (AuditLogUserRoleTO logTO : data){
if (audit.getUserName().equals(logTO.getUserName())){
sb1.add(StringUtils.isBlank(logTO.getAddRole()) ? "" : logTO.getAddRole());
sb2.add(StringUtils.isBlank(logTO.getDeleteRole()) ? "" : logTO.getDeleteRole());
}
}
temp.setAddRole(sb1.toString());
temp.setDeleteRole(sb2.toString());
tempList.add(temp);
}
把信息丢给sb1,sb2处理后,保证去重唯一,针对人员添加,对temp信息设置对应的新增,删除roleCode,给到最终的tempList,即实际传给审计处理信息。
因为上面的tempList仍然存在重复数据,原因是data是根据UserName循环设置的,上面最初设置时候,还没有对人去重,所以这个data重复,但保证了删除,添加role信息的统一。
需要再次进行去重操作,获取最终的result信息
System.out.println("tempList:"+tempList);
// 去重
List<AuditLogUserRoleTO> result = tempList.stream().collect(
Collectors.collectingAndThen(
Collectors.toCollection(
() -> new TreeSet<>(Comparator.comparing(AuditLogUserRoleTO::getUserName))),
ArrayList::new
)
);
System.out.println("result:"+result);
for (AuditLogUserRoleTO auditLogUserRoleTO : result) {
String addRole = auditLogUserRoleTO.getAddRole();
String deleteRole = auditLogUserRoleTO.getDeleteRole();
System.out.println("addRole"+(StringUtils.isBlank(addRole) ? "" : addRole));
System.out.println("deleteRole"+(StringUtils.isBlank(deleteRole) ? "" : deleteRole));
}
打印tempList信息,这时候将所有角色RoleCode汇总,但是因为根据userName,存在重复
tempList:
[AuditLogUserRoleTO(userName=Byron, personId=1, deleteRole=[A, B, C], addRole=[BA]), AuditLogUserRoleTO(userName=Byron, personId=1, deleteRole=[A, B, C], addRole=[BA]), AuditLogUserRoleTO(userName=Byron, personId=1, deleteRole=[A, B, C], addRole=[BA]), AuditLogUserRoleTO(userName=test, personId=2, deleteRole=[A], addRole=[]), AuditLogUserRoleTO(userName=Ftest, personId=3, deleteRole=[], addRole=[voidF])]
最终去重结果result,如下所示,通过collection相关操作得到,具体说明使用见最后
result:
[AuditLogUserRoleTO(userName=Byron, personId=1, deleteRole=[A, B, C], addRole=[BA]), AuditLogUserRoleTO(userName=Ftest, personId=3, deleteRole=[], addRole=[voidF]), AuditLogUserRoleTO(userName=test, personId=2, deleteRole=[A], addRole=[])]
addRole[BA]
deleteRole[A, B, C]
addRole[voidF]
deleteRole[]
addRole[]
deleteRole[A]
这样一来就能把所有的信息完成去重,并且提供相对准确,且待分隔的role信息。
参考以下做去重的lambda:
java8 stream两个集体交集、差集、并集操作 - 走看看
最后这一部分collectingAndThen的去重理解 记录一下
使用到了 collectingAndThen、toCollection、TreeSet这几点
核心在于:使用TreeSet去重,将TreeSet转换为List,这个理需要传入一个属性来比较作为比较器,使用public ArrayList<Collection<? extends E>c>将TreeSet放入构造器生成List
List<AuditLogUserRoleTO> result = tempList.stream().collect(
Collectors.collectingAndThen(
Collectors.toCollection(
() -> new TreeSet<>(Comparator.comparing(AuditLogUserRoleTO::getUserName))),
ArrayList::new
)
);
这一部分,可以使用普通集合:
TreeSet<AuditLogUserRoleTO> treeSet = new TreeSet<>(Comparator.comparing(AuditLogUserRoleTO::getUserName)));
for(AuditLogUserRoleTO tempData : tempList){
treeSet.add(tempData);
}
List<AuditLogUserRoleTO> result = new ArrayList<>(treeSet);
只要能够理解普通集合操作,name使用Stream流操作是,就要看对于API的使用是否熟悉,其实这个,这里需要理解collectingAndThen、toCollection、JDK8匿名函数。
关于collectingAndThen方法使用-----首先进行结果集的收集,然后将收集到的结果集进行下一步处理,看一下该信息需要传递的参数:
public static <T, A, R, RR> Collector<T, A, RR> collectingAndThen(Collector<T, A, R> var0, Function<R, RR> var1) {
Set var2 = var0.characteristics();
if (var2.contains(Characteristics.IDENTITY_FINISH)) {
if (var2.size() == 1) {
var2 = CH_NOID;
} else {
EnumSet var3 = EnumSet.copyOf(var2);
var3.remove(Characteristics.IDENTITY_FINISH);
var2 = Collections.unmodifiableSet(var3);
}
}
return new Collectors.CollectorImpl(var0.supplier(), var0.accumulator(), var0.combiner(), var0.finisher().andThen(var1), var2);
}
上面是它的源码,是Collector接口子类,所以还是对于Collector的处理,工具类中存在toList()、toSet、joining()、mapping()、collectingAndThen()等,几乎所有方法都可以使用,可以进行嵌套使用。第二个参数是一个Function函数,R apply(T t),这个是去重关键,ArrayList::new 调用的实参构造方法。
这里相当于通过Comparator获取去重内容,交给第二个参数Function函数,作为参数得到结果,就是Rapply(T t),将这个Comparator结果作为t放入。
对于toCollection是一个通过转换为集合的操作,在Collectors类里也有toList、toSet方法,但是不满足使用TreeSet获取集合,使用toCollection是一个通用方法,使用TreeSet收集,根据属性进行比较器比较,达到最终效果。
以上就是实现整个业务场景实现去重操作的过程其中,最后关于Collection这部分参考了,以下帖子,部分内容就是由他而来。
JDK8 Stream操作 collectingAndThen ------根据对象的属性进行去重操作_goodluckwj的博客-CSDN博客_collectingandthen