SpringAop切面实践-返回数据过滤填充
SpringAop切面实践-返回数据过滤填充
需求: 公司业务中引入工作流框架,涉及到代办任务的操作,但产品设计的是主要是业务单据为准,没有一个单独的待审核列表。所以无法用到
Activiti自带的查询代办任务的方法,鉴于各个模块中都存在工作流的运用,所以最好的办法只能是做到最小的侵入,和其他模块只关心自身业务,添加一个注解完事!前端的话就只要需要根据切面返回的数据中的某个字段,动态的展示审核按钮~
自定义注解
/**
* @author <a href="mailto:[email protected]">文刀草乙</a>
* @date 2021/11/3 16:49
* @project
* @Title: ProcDataFilter.java
**/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface ProcData {
/**
* 流程定义的Key ActTemplate中定义的Key 流程设计定义key
*
* @return
*/
public String procKey() default "";
/**
* 业务数据ID 启动流程时放的数据ID 需要反射到工作流服务中查询是否具有审核权限
*
* @return
*/
public String businessKey() default "";
}
切面逻辑
/**
* 带有流程的数据列表的审核权限的过滤
*
* @author <a href="mailto:[email protected]">刘艺</a>
* @date 2021/11/3 17:04
* @project
* @Title: ProcFilterAspect.java
**/
@Aspect
@Component
@Slf4j
@Order(9) // 定义切面的执行顺序
public class ProcFilterAspect {
@Resource
private RemoteActTaskApiService apiService; // 远程调用工作流服务进行数据是否具有审核权限的判断
/**
* 列表方法执行完成之后针对返回的数据做处理判断
*
* @param point
* @return java.lang.Object
* @author <a href="mailto:[email protected]">文刀草乙</a>
* @date 2021/11/3 17:10
*/
// 采用AfterReturning 通知在正常的业务数据处理完成之后做增强处理 其中returning = "returnData" 就是业务处理完成之后返回的列表数据
@AfterReturning(pointcut = "@annotation(com.qdd.act.api.annotation.ProcData)", returning = "returnData")
public void afterReturnData(JoinPoint point, Object returnData)
throws Throwable
{
//目的:获取切入点方法上自定义ProcData注解中procKey属性值
//1.1获取目标对象对应的字节码对象
Class<?> targetCls = point.getTarget().getClass();
//1.2获取目标方法对象
//1.2.1 获取方法签名信息从而获取方法名和参数类型
Signature signature = point.getSignature();
//1.2.1.1将方法签名强转成MethodSignature类型,方便调用
MethodSignature ms = (MethodSignature)signature;
//1.2.2通过字节码对象以及方法签名获取目标方法对象
Method targetMethod = targetCls.getDeclaredMethod(ms.getName(), ms.getParameterTypes());
//1.3获取目标方法对象上注解中的属性值
//1.2.3 获取方法上的自定义ProcData注解
ProcData procData = targetMethod.getAnnotation(ProcData.class);
//1.2.4 获取自定义注解中procKey属性的值
String procKey = procData.procKey();
String businessKey = procData.businessKey();
// 如果返回的是TableInfo 判断业务数据返回的是TableInfo 对象
if (returnData instanceof TableDataInfo) {
TableDataInfo dataInfo = (TableDataInfo)returnData;
List<?> rows = dataInfo.getRows();
if (dataInfo.getCode() == HttpStatus.SUCCESS && CollectionUtils.isNotEmpty(rows)) {
// 开始处理返回的业务数据
List<?> returnDatas = handleData(dataInfo.getRows(), procKey, businessKey);
dataInfo.setRows(CollectionUtils.isNotEmpty(returnDatas) ? returnDatas : rows);
}
}
}
/**
* 处理返回的List数据
*
* @param rows
* @param key
* @param businessKey
* @return void
* @author <a href="mailto:[email protected]">文刀草乙</a>
* @date 2021/11/3 18:01
*/
public List<?> handleData(List<?> rows, String key, String businessKey)
{
String currentUserId = String.valueOf(SecurityUtils.getUserId());
ArrayList<ProcListHandleData> lists = new ArrayList<>();
for (int i = 0; i < rows.size(); i++) {
Object o = rows.get(i);
try {
String id = Objects.requireNonNull(getGetMethod(o, businessKey)).toString();
if (StringUtils.isNotBlank(id)) {
ProcListHandleData procListHandleData = new ProcListHandleData();
procListHandleData.setBusinessKey(Long.valueOf(id));
procListHandleData.setProcDefKey(key);
procListHandleData.setCurrentUserId(currentUserId);
lists.add(procListHandleData);
}
}
catch (NoSuchMethodException | IllegalAccessException e) {
e.printStackTrace();
}
catch (InvocationTargetException e) {
e.printStackTrace();
}
catch (Exception e) {
e.printStackTrace();
}
}
if (CollectionUtils.isNotEmpty(lists)) {
// 远程调用处理是否具有审核权限的逻辑
R<List<ProcListHandleData>> handleProList = apiService.handleProcList(lists);
if (handleProList.getCode() == HttpStatus.SUCCESS) {
return handleButtonShow(rows, handleProList.getData(), businessKey);
}
}
return new ArrayList<>();
}
/**
* 根据远程调用的结果来处理按钮到时显示不显示
*
* @param rows
* @param lists
* @param businessKey
* @return void
* @author <a href="mailto:[email protected]">文刀草乙</a>
* @date 2021/11/4 9:53
*/
public List<Object> handleButtonShow(List<?> rows, List<ProcListHandleData> lists, String businessKey) {
List<Object> objects = new ArrayList<>();
for (Object row : rows) {
try {
String id = Objects.requireNonNull(getGetMethod(row, businessKey)).toString();
if (StringUtils.isNotBlank(id)) {
ProcListHandleData handleData = (ProcListHandleData)lists.stream().filter(e -> Objects.equals(id, String.valueOf(e.getBusinessKey()))).distinct().toArray()[0];
Map<String, Object> propertiesMap = new HashMap<>(1);
propertiesMap.put("showAuditButton", handleData.getShowAuditButton());
Object obj = PropertyAppender.generate(row, propertiesMap);
objects.add(obj);
}
}
catch (Exception e) {
e.printStackTrace();
}
}
return objects;
}
/**
* 根据属性,获取get方法
*
* @param ob
* @param name
* @return java.lang.Object
* @author <a href="mailto:[email protected]">刘艺</a>
* @date 2021/11/4 14:12
*/
public static Object getGetMethod(Object ob, String name)
throws Exception
{
Method[] m = ob.getClass().getMethods();
for (int i = 0; i < m.length; i++) {
if (("get" + name).equalsIgnoreCase(m[i].getName())) {
return m[i].invoke(ob);
}
}
return null;
}
校验是否具有审核权限
/**
* 根据传过来数据筛选是否展示审核按钮
*
* @param dataList
* @return com.qdd.common.core.domain.R<java.util.List < com.qdd.act.api.domain.ProcListHandleData>>
* @author <a href="mailto:[email protected]">文刀草乙</a>
* @date 2021/11/4 9:19
*/
@Override
public R<List<ProcListHandleData>> handleProcList(List<ProcListHandleData> dataList) {
RequestContextHolder.getRequestAttributes();
// 获取当前登陆人
Long userId = SecurityUtils.getUserId();
List<BizNode> bizNodes = (List<BizNode>)bizNodeService.selectBizNodeByProcInfo(new BizNode().setProcKey(dataList.get(0).getProcDefKey()));
for (ProcListHandleData procListHandleData : dataList) {
BizBusiness business = businessService.selectBizBusinessByBusinessKey(new BizAudit().setBusinessKey(procListHandleData.getBusinessKey()).setProcDefKey(procListHandleData.getProcDefKey()));
if (Objects.nonNull(business)) {
TaskEntity currentTask = getCurrentTask(business.getProcInstId());
if (Objects.nonNull(currentTask)) {
boolean result = checkCurrenTaskAndHisReapt(business, currentTask, userId);
if (!result) {
Object[] objects = bizNodes.stream().filter(e -> Objects.equals(currentTask.getTaskDefinitionKey(), e.getNodeId())).distinct().toArray();
BizNode node = (objects.length >= 1) ? (BizNode)objects[0] : new BizNode();
// checkAuditUse() 主要检验当前登录人 角色、岗位、指定人是否是在审核人权限列表中 ,校验结果放入到setShowAuditButton结果中
procListHandleData.setShowAuditButton((HttpStatus.SUCCESS == checkAuditUser(node, Objects.isNull(userId) ?
Long.parseLong(procListHandleData.getCurrentUserId()) :
userId).getCode()) ? "1" : "0");
}
}
}
}
// 将没有审核权限的或者是为null的放到最后 友好展示给前端
return R.ok(dataList.stream().sorted(Comparator.comparing(ProcListHandleData::getShowAuditButton, Comparator.<String>nullsLast(String::compareTo))).collect(Collectors.toList()));
}
食用说明
后端在请求审核列表的Controller方法上添加注解
@ProcData(procKey = "流程定义的Key", businessKey = "启动流程时放入的业务数据ID 的字段名")如下
@ProcData(procKey = "GOODS_CHANGE_AUDIT", businessKey = "id") @RequestMapping("goodsAuditList")
public TableDataInfo goodsAuditList(@RequestBody GoodsChangeAudit goodsChangeAudit)
{
startPage();
List<GoodsChangeAudit> goodsChangeAuditList=qddGoodsService.goodsAuditList(goodsChangeAudit);
return getDataTable(goodsChangeAuditList);
}
前端根据返回
rowsList数据中的showAuditButton字段展示审核按钮1-展示 0-不展示