最近项目中大量使用了流程,流程框架采用的是activity,客户要求把表单数据和对应的流程审批数据导出为pdf,简单的做法就是扩展表单的类,把每一个流程节点作为一个属性添加到类,但是有个问题是:流程不确定,后续可能会修改,导致流程节点无法写死到类上。
然后想到可以利用cglib的动态生成类和属性的方法,动态的把流程节点作为属性添加到类,同时为了方便维护,使用自定义注解和aop统一进行处理。自定义注解和aop的使用可参考SpringAOP+自定义注解实现日志功能,这里不详细说了,下面说下实现思路和实现代码,代码只粘贴了主要部分。
在要增加流程节点Controller的方法上添加自定义的注解,当收到请求时进入AOP,配合注解获取要处理的对象和其流程id的值,通过流程id查询到包含流程节点数据的map,把对象和map使用cglib的动态生成类和属性的方法生成对象并返回。
Annotation:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RelationFiled {
/**
* 视图模型对象中数据的key
* @return
*/
String attributeName();
/**
* 数据对象的属性(流程实例id)
* @return
*/
String propertyName() default "procInsId";
/**
* 数据对象要添加的字段名称
* @return
*/
String[] fields() default {};
}
Controller:
@RelationFiled(attributeName="process",fields= {"startAudit","startAuditName"})
@RequiresPermissions("xx:xxx:exportPdf")
@RequestMapping(value = "exportPdf")
public String exportPdf(Process process, Model model) {
model.addAttribute("process", process);
return "modules/gz/process/exportPdf";
}
AOP:
@Around("actPointcut()")
public Object doAround(ProceedingJoinPoint pjp){
Object obj = null;
try {
//执行切入点方法
obj = pjp.proceed();
//获取执行方法
MethodSignature ms = (MethodSignature)pjp.getSignature();
Method method = pjp.getTarget().getClass().getDeclaredMethod(ms.getName(), ms.getParameterTypes());
//获取执行方法RelationFiled注解
RelationFiled rf = method.getAnnotation(RelationFiled.class);
//获取方法参数
Object[] args = pjp.getArgs();
Object object = null;
ModelMap model = null;//根据自己项目实际情况而定,比如使用的是ModelAndView这里就是ModelAndView
for (Object arg : args) {
if (arg instanceof Model){
model = (ModelMap) arg;
object = model.get(rf.attributeName());//通过rf.attributeName()自定义注解参数值获取要生成属性的对象
break;
}
}
//根据反射获取流程id
Field field = object.getClass().getDeclaredField(rf.propertyName());
field.setAccessible(true);
Object procInsId = field.get(object);
//根据流程id获取流程数据
Map<String, Object> map = actTaskService.getMap(procInsId == null?null:procInsId.toString());
//添加指定生成的属性到map,model中如有指定属性的数据可同时进行处理
String[] fields = rf.fields();
for(String f : fields) {
//不覆盖存在的属性
if(!map.containsKey(f)) {
map.put(f, "");
}
}
//生成属性并返回
model.addAttribute(mi.attributeName(), PropertyUtils.generate(object, map));
} catch (Throwable e) {
e.printStackTrace();
}
return obj;
}
PropertyUtils:
package com.xx.xx.utils;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import org.springframework.cglib.beans.BeanGenerator;
import org.springframework.cglib.beans.BeanMap;
public class PropertyUtils {
private static final class DynamicBean {
private Object object;
private BeanMap beanMap;
//创建对象和属性map
private DynamicBean(Class<?> superclass, Map<String, Class<?>> propertyMap) {
this.object = generateBean(superclass, propertyMap);
this.beanMap = BeanMap.create(this.object);
}
//为对象属性赋值
private void setValue(String property, Object value) {
beanMap.put(property, value);
}
private Object getObject() {
return this.object;
}
//创建对象
private Object generateBean(Class<?> superclass, Map<String, Class<?>> propertyMap) {
BeanGenerator generator = new BeanGenerator();
if (null != superclass) {
generator.setSuperclass(superclass);
}
BeanGenerator.addProperties(generator, propertyMap);
return generator.create();
}
}
/**
* 动态创建对象
* @param valueMap 动态对象的属性和值
* @return
*/
public static Object generate(Map<String, Object> valueMap) {
return generate(null, valueMap);
}
/**
* 动态创建对象,可继承其它对象的属性
* @param object 被继承属性的对象
* @param valueMap 动态对象的属性和值
* @return
*/
public static Object generate(Object object, Map<String, Object> valueMap) {
Map<String,Class<?>> fieldMap = new HashMap<String, Class<?>>();//要创建的属性
valueMap.forEach((k, v) -> {
if(k == null) {
}else if(v == null) {
fieldMap.put(k, Object.class);
}else {
fieldMap.put(k, v.getClass());
}
});
Class<?> clazz = null;
Class<?> superclass = null;
if(object != null) {
clazz = object.getClass();
superclass = clazz;
}
//获取对象属性的值并保存到valueMap
while (clazz != null) {
for (Field field : clazz.getDeclaredFields()) {
try {
field.setAccessible(true);
valueMap.put(field.getName(), field.get(object));
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
clazz = clazz.getSuperclass();
}
//生成动态对象
DynamicBean dynamicBean = new DynamicBean(superclass,fieldMap);
//为动态对象属性赋值
valueMap.forEach((k, v) -> {
dynamicBean.setValue(k, v);
});
return dynamicBean.getObject();
}
}