1、Controller
@RestController
public class ActivitiController extends BaseController {
/**
* Activiti 框架提供的操作 Repository 系列表的 Service
*/
@Autowired
private RepositoryService repositoryService;
@RequestMapping("/activiti/findProcessListPage/{startIndex}/{pageSize}")
public Object findProcessListPage(@PathVariable("startIndex") Integer startIndex, @PathVariable("pageSize") Integer pageSize) {
List<ProcessDefinition> processDefinitions = repositoryService
.createProcessDefinitionQuery()
.listPage(startIndex, pageSize);
System.out.println("---------------" + processDefinitions );
return processDefinitions ;
}
}
2、运行结果
java 控制台消息提示,可以正确的查询出 processDefinitions 结果:
浏览器提示错误消息如下:
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Thu Nov 21 09:27:46 CST 2019
There was an unexpected error (type=Internal Server Error, status=500).
Could not write JSON: (was java.lang.NullPointerException); nested exception is com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: java.util.ArrayList[0]->org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntityImpl["identityLinks"])
org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: (was java.lang.NullPointerException); nested exception is com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: java.util.ArrayList[0]->org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntityImpl["identityLinks"])
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:296)
at org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:104)
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:295)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:181)
at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:82)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:124)
......
Caused by: com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: java.util.ArrayList[0]->org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntityImpl["identityLinks"])
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:394)
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:353)
at com.fasterxml.jackson.databind.ser.std.StdSerializer.wrapAndThrow(StdSerializer.java:316)
......
Caused by: java.lang.NullPointerException
at org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntityImpl.getIdentityLinks(ProcessDefinitionEntityImpl.java:66)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:567)
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:688)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:721)
... 108 more
3、解决方法
将查询到每条结果封装到一个 Map 中,进多条结果封装到 List 中,将封装的结果返回即可,具体如下:
@RestController
public class ActivitiController extends BaseController {
/**
* Activiti 框架提供的操作 Repository 系列表的 Service
*/
@Autowired
private RepositoryService repositoryService;
@RequestMapping("/activiti/findProcessListPage/{startIndex}/{pageSize}")
public Object findProcessListPage(@PathVariable("startIndex") Integer startIndex, @PathVariable("pageSize") Integer pageSize) {
List<ProcessDefinition> processDefinitions = repositoryService
.createProcessDefinitionQuery()
.listPage(startIndex, pageSize);
// ============= 对上面查询结果进行封装 ==================
List<Map<String, Object>> pdResult = new ArrayList<>();
for (ProcessDefinition processDefinition : processDefinitions) {
Map<String, Object> pdMap = new HashMap<>();
pdMap.put("id", processDefinition.getId());
pdMap.put("key", processDefinition.getKey());
pdMap.put("name", processDefinition.getName());
pdMap.put("version", processDefinition.getVersion());
pdMap.put("deploymentId", processDefinition.getDeploymentId());
pdResult.add(pdMap);
}
// ================== 封装完成 =========================
System.out.println("---------------" + pdResult);
return pdResult;
}
}
运行结果如下:
[{
“deploymentId”:“d05c66ec-09ad-11ea-a748-4ccc6ac9b5ee”,
“name”:“请假审批流程”,
“id”:“holiday:1:d07a9d4f-09ad-11ea-a748-4ccc6ac9b5ee”,
“version”:1,
“key”:“holiday”
}]
4、通用的封装方法
使用反射动态获取类中的 get 方法,将方法的返回值进行封装,如下:(此封装方法也可用于activiti其他的查询返回json)
public class Util {
public static List<Map<String, Object>> activitiResult(List<?> objs) {
// 用于存放多个对象的集合
List<Map<String, Object>> pdResult = new ArrayList<>();
// 遍历方法参数中的集合
for (Object obj : objs) {
// 用于封装单个对象 get 方法返回值的 Map 集合
Map<String, Object> pdMap = new HashMap<>();
// 通过反射获取该对象的方法对象数组
Method[] methods = obj.getClass().getMethods();
// 遍历方法对象数组
for (Method method : methods) {
// 获取方法名称
String methodName = method.getName();
// 判断该方法是否名称不为 null ,并且名称是以 get 开头,满足条件进入 if 中
if (methodName != null && methodName.startsWith("get")) {
// 设置方法的访问权限
method.setAccessible(true);
try {
// 将方法名的 get 前缀去掉,并增加 pd 前缀
String pdKey = "pb".concat(methodName.substring(3));
// 将 get 方法的名称作为 Map 的 key,将返回值作为 value 进行封装
pdMap.put(pdKey, method.invoke(obj, null));
} catch (Exception e) {
//输出异常,由于使得后台过乱,所以关掉
// e.printStackTrace();
}
}
}
// 将封装好的 Map 集合添加到 List 集合中
pdResult.add(pdMap);
}
return pdResult;
}
}
在需要封装结果的方法中调用此方法即可:
public Result queryProcesses() {
//1.得到ProcessDefinitionQuery对象,可以认为它就是一个查询器
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
//2.设置条件,并查询出当前的所有流程定义 查询条件:流程定义的key=holiday
//orderByProcessDefinitionVersion() 设置排序方式,根据流程定义的版本号进行排序
List<ProcessDefinition> list = processDefinitionQuery
// .processDefinitionKey("holiday") //查询固定流程
.orderByProcessDefinitionVersion()
.desc().list();
Result res=new Result();
res.setFlag("1");
res.setMsg("查询成功");
//该list无法返回为json会报错,将它封装为List<Map<String, Object>>再返回,使用通用封装类Util进行封装
res.setResult(Util.activitiResult(list));
return res;
}
运行结果如下:
[{
“pbCategory”:“http://www.activiti.org/testm1574044576798”,
“pbDeploymentId”:“d05c66ec-09ad-11ea-a748-4ccc6ac9b5ee”,
“pbPersistentState”:{
“suspensionState”:1,“category”:
“http://www.activiti.org/testm1574044576798”
},“pbHasStartFormKey”:false,“pbSuspensionState”:1,
“pbName”:“请假审批流程”,
“pbDiagramResourceName”:“process/holiday.png”,
“pbVersion”:1,
“pbKey”:“holiday”,
“pbResourceName”:“process/holiday.bpmn”,
“pbTenantId”:""
}]
以上内容转载自优快云博主「yage124」的原创文章,原文链接:https://blog.youkuaiyun.com/yage124/article/details/103176405
5.原因分析
打开activiti的一个实体类org.activiti.engine.task,如下所示,并不像我们平时的实体类,get和set方法在一个类中,他是分不同种的接口,可能就是由于这个原因使得无法返回json格式数据。