# 系统集成接入

# 系统架构

应用接入交我办是通过实现接口规范中定义的 5 种接口中的一个或多个来完成的,当用户在交我办的办事大厅请求可办、待办、已办事项时,交我办的任务集成 Api 会将请求分派给所有接入交我办的应用,调用应用实现的可办、待办、已办接口获取该应用的数据,经过汇总后展现给用户。

由这张图也可以得知接口调用的时机即用户访问交我办网站或者 APP 的时候,用户在页面上每次刷新都会调用接口。

# 实现接口

根据需求,应用接入交我办需要实现的接口包括可办、待办、进行中、已完成、已办、任务详情接口,以下将分别说明实现方法。

# 可办

可办任务是指用户可以发起办理的业务,如果应用希望可办任务出现在办事大厅里就要实现可办接口。

以下将给出可办任务接口实现的详细参数和示例代码,除此之外您还需要关注多语言最佳实践接口安全测试检查上线申请等内容。

可办接口需要支持三个查询参数:userId、occupy、locale,具体含义可参考此处文档。

我们的接口需要根据用户账号、岗位以及使用语言返回可办列表,接口返回的可办对象的数据结构定义如下,可办对象的示例代码请参考此处 (opens new window)

App
{
  "id":{guid}, // 无意义的唯一 id,应为 GUID 格式,并保持稳定
  "name":{string}, //显示业务分类名称,如:奖学金申请
  "uri":{string}, //启动 uri
  "code":{string}, //应用代码,可用于部分 api 调用,表示该 app 的发布版
  "abbreviation":{string}, //缩略名
  "description":{string}, //服务摘要
  "tags":{string}, //应用标签,可以有多个,以逗号分隔
  "icon":{uri}, //图标 uri
  "palette":{string}, //调色板颜色,形如:#ff0000
  "department":{string}, //负责部门
  "contact":{string}, //联系人及其方式描述
  "online":{long}, //上线时间的时间戳,unix 时间戳(秒)
  "offline":{long}, //下线时间的时间戳,unix 时间戳(秒)
  "recommend":{integer}, //推荐度,可办任务按推荐度逆序排列
  "rating":{integer}, //评价汇总
  "rated":{integer}, //评价次数
  "visible":{boolean}, //是否可见
  "ready":{boolean}, //是否提供线上服务。默认为 false。交我办网站和 App 会特殊显示非线上服务
  "system":{string} //所属系统。工作流应用的此字段为空;用于区分管理学校内其他系统提供的“可办“
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

以下给出了可办接口代码实现示例,代码中TaskApiHandler (opens new window)在下文中会有更详细的说明。

示例 可办接口实现示例

@Resource
private TaskApiHandler taskApiHandler;

private static final String USER_ID = "userId";
private static final String OCCUPY = "occupy";
private static final String LOCALE = "locale";

/**
 * 交我办获取可办数据
 *
 * @param userId 用户账号
 * @param occupy 用户岗位信息
 * @param locale 语言
 * @return 可办列表
 */
@RequestMapping(value = "/apps", method = RequestMethod.GET)
public TaskResponse<App> getTaskAppsList(@RequestParam(value = USER_ID) String userId,
                                            @RequestParam(value = OCCUPY) String occupy,
                                            @RequestParam(value = LOCALE, required = false, defaultValue = "zh") String locale) {
    try {
        // 可根据用户账号和occupy中的岗位获取可办,如果可办数据支持双语,getAppList方法请再传递locale参数
        List<App> appsList = taskApiHandler.getAppList(userId, occupy);
        logger.info("获取可办, 账号:{}, 数量:{}", userId, appsList.size());
        return new TaskResponse<>(0, appsList.size(), appsList);
    } catch (Exception e) {
        logger.error(String.format("获取可办失败. 错误信息: %s", e.getMessage()), e);
        return new TaskResponse<>(1, e.getMessage());
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# 可办对象说明

接口返回的 App 对象关键字段只有两个:id(GUID 格式)和 uri。接口返回的可办的 id 必须在交我办平台中注册过才会生效,所以在集成接入可办时需要将您所有应用的 id、名称(如果要支持英语的话请提供中英文名称)和发起链接以邮件的形式告知管理员,这也就意味着您的每个可办数据的 id 必须稳定唯一。如果对可办事项的分类目录以及目录中的排序有要求的话也可以在申请邮件中一起说明,这些内容我们会注册在交我办平台上,接口返回的数据就无须包括这些信息了。

# 待办

待办任务指正在等待用户处理的业务环节,如果想在交我办待办事项中看到应用的待办任务就需要实现待办接口。

以下将给出待办任务接口实现的详细参数和示例代码,除此之外您还需要关注多语言最佳实践待办更新待办完成接口安全测试检查上线申请等内容。

待办接口需要支持的参数是 userId、locale,根据用户账号获取待办,如果不需要支持多语言那么仅 userId 参数支持即可。

接口返回的待办对象的数据结构如下,待办对象示例代码可参考此处 (opens new window)

Task
{
  "id":{guid}, // 无意义的唯一 id,应为 GUID 格式,并保持稳定
  "name":{string}, //当前任务名,如:"待审核"、"申请单填写"
  "uri":{string}, //展示表单所需的 uri
  "tags":{string}, //该任务的标签,可以有多个,以逗号分隔
  "description":{string}, //摘要
  "process":{process 对象}, //所属实例,见Process对象定义
  "assignUser":{profile 对象}, //指派给的用户,可能为空,表示未指定具体用户,见Profile对象定义
  "assignTime":{long}, //指派时间,unix 时间戳(秒)
  "actionUser":{profile 对象}, //实际完成的用户,仅在进行中任务和已完成任务中有效
  "actionTime":{long}, //完成时间,unix 时间戳(秒)
  "actionName":{string}, //办理时选择的动作名称
  "expireTime":{long}, //超时时间,unix 时间戳(秒)
  "remark":{string}, //办理用户填写的备注信息
  "status":{int}, //状态:1.待做,2.已做,3.草稿
  "actions":[{ //可一键办理的步骤
    "id":{integer}, //actionId
    "name":{string}, //显示名
    "code":{string}, //action code
    "remarkRequired":{boolean}, //是否备注必填
  }]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

其中涉及到的Process对象结构参见已办章节文档,Profile对象结构如下:

Profile
{
  "name":{string}, //用户姓名
  "account":{string} //用户的 jAccount 账号
}
1
2
3
4
5

待办接口实现示例如下:

示例 待办接口实现示例
/**
 * 交我办获取待办数据
 *
 * @param userId 用户账号
 * @param locale 语言
 * @return 待办列表
 */
@RequestMapping(value = "/todo", method = RequestMethod.GET)
public TaskResponse<Task> getTaskTodoList(@RequestParam(value = USER_ID) String userId,
                                            @RequestParam(value = LOCALE, required = false, defaultValue = "zh") String locale) {
    try {
        List<Task> todoList = taskApiHandler.getTodoList(userId);
        logger.info("获取待办任务, 账号:{}, 数量:{}", userId, todoList.size());
        return new TaskResponse<>(0, todoList.size(), todoList);
    } catch (Exception e) {
        logger.error(String.format("获取待办任务失败. 错误信息: %s", e.getMessage()), e);
        return new TaskResponse<>(1, e.getMessage());
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 待办任务对象说明

待办对象比较重要的字段说明如下

名称 说明 必填
id 无意义的唯一 id,GUID 格式
name 任务名称(显示在待办事项列表中)
uri 任务办理 uri
assignTime 任务指派时间,unix时间戳(秒)(显示在待办事项列表中)
status 任务状态(待办任务为 1)
tags 任务标签,有标签后分类更明确,缺省会有一个标签,如果想自定义请修改该字段
process 任务所属实例(Process)(实例名称和流水号显示在待办事项列表中)

实例 Process 对象比较重要的字段说明如下

名称 说明 必填
id 无意义的唯一 id,GUID 格式
name 实例名称(显示在待办事项列表中)
owner 所属用户(Profile 对象),用于区分 my 待办事项中是我申请的事项还是等我处理的事项
entry 实例流水号,整型数字,没有可不填

用户 Profile 对象说明如下

名称 说明 必填
account jAccount 账号
name 姓名

待办事项列表和接口返回的数据对应关系如下图

# 进行中、已完成、已办

进行中任务是指用户曾办理目前尚未完成的业务流程;已完成任务是指用户曾办理,且当前已完成的业务流程;已办任务是指用户曾办理的业务流程,不区分是否已经完成,所以已办接口返回的数据为进行中数据加上已完成数据。

进行中、已完成、已办这三个任务接口为一组,如果想在交我办已办事项中看到应用已办任务需要同时实现进行中、已完成、已办三个接口

以下将给出三种任务接口实现的详细参数和示例代码,除此之外您还需要关注多语言最佳实践接口安全测试检查上线申请等内容。

这三个接口需要支持的查询参数也是一样的,包括 userId、start、limit、order、orderTimes、keyword、sep,这些参数的具体含义参考此处,注意这些参数除 orderTimes 以外必须全部支持

接口返回的实例对象的数据结构如下,实例对象代码示例可参考此处 (opens new window)

Process
{
  "id":{guid}, // 无意义的唯一 id,应为 GUID 格式,并保持稳定
  "name":{string}, //流程实例的名称
  "uri":{string}, //查看流程实例用到的 uri
  "tags":{string}, //该流程的标签,可以有多个,以逗号分隔
  "entry":{string}, //流程流水号
  "create":{long}, //流程的创建时间,unix 时间戳(秒)
  "update":{long}, //流程最后操作时间,unix 时间戳(秒)
  "sort":{long}, //流程的排序时间,unix 时间戳(秒)。见接口参数中对order的要求,该属性应提供实际用于排序的时间值。
  "app":{app 对象}, //所属应用,见 App 对象
  "owner":{profile 对象}, //所属用户,见 Profile 对象
  "status":{string}, //流程状态:doing、done、killed
  "rate":{int}, //评价星级,1-5
  "review":{string}, //评价内容
  "pendingTasks":{string}, //当前的待办
  "tasks":[{task 对象}] //任务列表
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

以下给出三种接口实现示例

示例 进行中接口实现示例
private static final String USER_ID = "userId";
private static final String OCCUPY = "occupy";
private static final String LOCALE = "locale";
private static final String START = "start";
private static final String LIMIT = "limit";
private static final String ORDER = "order";
private static final String KEYWORD = "keyword";
private static final String ORDER_TIMES = "orderTimes";
private static final String SEP = "sep";

/**
 * 交我办获取进行中数据
 *
 * @param userId     用户账号
 * @param locale     语言
 * @param start      开始行
 * @param limit      返回行数
 * @param order      排序
 * @param orderTimes 返回数据的时间范围
 * @param keyword    搜索关键字
 * @param sep        返回数据是否是别人发起的
 * @return 进行中任务列表
 */
@RequestMapping(value = "/doing", method = RequestMethod.GET)
public TaskResponse<Process> getTaskDoingList(@RequestParam(value = USER_ID) String userId,
                                                @RequestParam(value = LOCALE, required = false, defaultValue = "zh") String locale,
                                                @RequestParam(value = START, defaultValue = "0", required = false) int start,
                                                @RequestParam(value = LIMIT, defaultValue = "20", required = false) int limit,
                                                @RequestParam(value = ORDER, required = false) String order,
                                                @RequestParam(value = ORDER_TIMES, required = false) String orderTimes,
                                                @RequestParam(value = KEYWORD, required = false) String keyword,
                                                @RequestParam(value = SEP, required = false) Boolean sep) {
    try {
        List<Process> doingList = taskApiHandler.getDoingList(userId, start, limit, order, orderTimes, keyword, sep);
        logger.info("获取进行中任务, 账号:{}, 数量:{}, 起始行:{}, 返回行数:{}, 排序:{}, 时间返回:{}, 关键字:{}, 是否别人发起:{}",
                userId, doingList.size(), start, limit, order, orderTimes, keyword, sep);
        return new TaskResponse<>(0, doingList.size(), doingList);
    } catch (Exception e) {
        logger.error(String.format("获取进行中任务失败. 错误信息: %s", e.getMessage()), e);
        return new TaskResponse<>(1, e.getMessage());
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
示例 已完成接口实现示例
/**
 * 交我办获取已完成数据
 *
 * @param userId     用户账号
 * @param locale     语言
 * @param start      开始行
 * @param limit      返回行数
 * @param order      排序
 * @param orderTimes 返回数据的时间范围
 * @param keyword    搜索关键字
 * @param sep        返回数据是否是别人发起的
 * @return 已完成任务列表
 */
@RequestMapping(value = "/done", method = RequestMethod.GET)
public TaskResponse<Process> getTaskDoneList(@RequestParam(value = USER_ID) String userId,
                                                @RequestParam(value = LOCALE, required = false, defaultValue = "zh") String locale,
                                                @RequestParam(value = START, defaultValue = "0", required = false) int start,
                                                @RequestParam(value = LIMIT, defaultValue = "20", required = false) int limit,
                                                @RequestParam(value = ORDER, required = false) String order,
                                                @RequestParam(value = ORDER_TIMES, required = false) String orderTimes,
                                                @RequestParam(value = KEYWORD, required = false) String keyword,
                                                @RequestParam(value = SEP, required = false) Boolean sep) {
    try {
        List<Process> doneList = taskApiHandler.getDoneList(userId, start, limit, order, orderTimes, keyword, sep);
        logger.info("获取已完成任务, 账号:{}, 数量:{}, 起始行:{}, 返回行数:{}, 排序:{}, 时间返回:{}, 关键字:{}, 是否别人发起:{}",
                userId, doneList.size(), start, limit, order, orderTimes, keyword, sep);
        return new TaskResponse<>(0, doneList.size(), doneList);
    } catch (Exception e) {
        logger.error(String.format("获取已完成任务失败. 错误信息: %s", e.getMessage()), e);
        return new TaskResponse<>(1, e.getMessage());
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
示例 已办接口实现示例
/**
 * 交我办获取已办数据
 *
 * @param userId     用户账号
 * @param locale     语言
 * @param start      开始行
 * @param limit      返回行数
 * @param order      排序
 * @param orderTimes 返回数据的时间范围
 * @param keyword    搜索关键字
 * @param sep        返回数据是否是别人发起的
 * @return 已办任务列表
 */
@RequestMapping(value = "/complete", method = RequestMethod.GET)
public TaskResponse<Process> getTaskCompleteList(@RequestParam(value = USER_ID) String userId,
                                                    @RequestParam(value = LOCALE, required = false, defaultValue = "zh") String locale,
                                                    @RequestParam(value = START, defaultValue = "0", required = false) int start,
                                                    @RequestParam(value = LIMIT, defaultValue = "20", required = false) int limit,
                                                    @RequestParam(value = ORDER, required = false) String order,
                                                    @RequestParam(value = ORDER_TIMES, required = false) String orderTimes,
                                                    @RequestParam(value = KEYWORD, required = false) String keyword,
                                                    @RequestParam(value = SEP, required = false) Boolean sep) {
    try {
        List<Process> completeList = taskApiHandler.getCompleteList(userId, start, limit, order, orderTimes, keyword, sep);
        logger.info("获取已办任务, 账号:{}, 数量:{}, 起始行:{}, 返回行数:{}, 排序:{}, 时间返回:{}, 关键字:{}, 是否别人发起:{}",
                userId, completeList.size(), start, limit, order, orderTimes, keyword, sep);
        return new TaskResponse<>(0, completeList.size(), completeList);
    } catch (Exception e) {
        logger.error(String.format("获取已办任务失败. 错误信息: %s", e.getMessage()), e);
        return new TaskResponse<>(1, e.getMessage());
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# 实例对象说明

在待办接口文档里我们已经说明过了实例(Process)对象部分字段,这里我们再给出在办、已办、已完成接口中实例完整字段的说明

名称 说明 必填
id 无意义的唯一 id,GUID 格式
name 实例名称(显示在待办事项列表中)
uri 查看流程实例用到的 uri
owner 所属用户(Profile 对象)
entry 实例流水号,整型数字,没有可不填
app 所属应用(App 对象)
create 实例创建时间 ,unix时间戳(秒)
update 实例最后操作时间,unix时间戳(秒)
sort 实例排序时间 ,unix时间戳(秒)
tasks 实例任务列表,没有详细任务列表或不显示可传空数组
实现了详情接口的话传null,不推荐一次全给出所有任务列表
status 状态:doing、done、killed
  • app 字段需要填写 App.name,这会出现在已办事项列表的来源栏
  • sort 是排序时间,根据 order 查询参数确定一个排序方法后,每个实例实际参与排序的时间填到 sort 字段,无论是按创建时间、最后更新时间还是最后一次参与任务的时间,都要将参与排序的时间填到 sort 里,sort 字段不填时任务集成 API 会根据 order 参数自行计算,不过接口实现时必须按 order 参数不同值来确定从数据库查询时采用的排序。
  • 对于 tasks 字段,如果您的已办事项没有或者不想列出详细的任务列表,那么可以传递一个空数组。如果有任务列表且实现了任务详情接口,那么 tasks 请返回 null,此时用户点击已办任务时会请求任务详情接口。不推荐直接将实例的任务详情直接填在 tasks 数组里直接返回,因为这可能会引起查询效率问题。

进行中、已完成、已办事项列表和接口返回的数据对应关系如下图

# 详情

交我办已办事项页面点击已办事项的状态可以查看该事项的详细步骤,如图所示:

如果您想要列出详细任务列表就需要实现详情接口,如果详细任务列表不存在或者不想展示就在已办接口返回的Process对象的tasks字段返回空数组,需要展示任务列表则tasks返回null。

实例任务详情接口需要接收id参数表示查询该 id 实例详情数据,另外 userId 参数可用于验证是否这个实例有该 userId 账号的参与,id 参数可以用查询参数的形式,也可以用路径参数的形式。接口返回的也是 Process 对象,其中的 tasks 字段填充了实例任务列表,是Task对象,和待办任务接口返回的Task对象相比需要填的字段有所不同。以下给出详情接口的代码实现。

/**
 * 交我办获取已办任务详情
 *
 * @param id     任务id
 * @param userId 用户账号
 * @return 返回任务详情
 */
@RequestMapping(value = "/process/{id}", method = RequestMethod.GET)
public TaskResponse<Process> getTaskProcessList(@PathVariable("id") String id, @RequestParam(value = USER_ID) String userId) {
    try {
        List<Process> processList = taskApiHandler.getProcessList(id, userId);
        logger.info("获取任务详情,id:{} 数量:{}", id, processList.size());
        return new TaskResponse<>(0, processList.size(), processList);
    } catch (Exception e) {
        logger.error(String.format("获取任务详情失败. 错误信息: %s", e.getMessage()), e);
        return new TaskResponse<>(1, e.getMessage());
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 详情接口返回的 Task 对象说明

名称 说明 必填
id 无意义的唯一 id,GUID 格式
name 任务名称
uri 任务查看 uri
assignTime 任务指派时间 ,unix时间戳(秒)
actionTime 任务完成时间,unix时间戳(秒)
actionUser 完成的用户(Profile)
actionName 办理时用户选择的动作名称

其中 actionTime、actionUser、actionName 如果办理过就必填,还没办理就不填。

# 最佳实践

当接口返回的数据在您的数据库中是从不同的表查询再合并获取的时候(例如您的系统中有三种类型的待办数据,要从三个表里查询结果),同步的依次查询所有表再合并数据显示会让接口响应时间变慢,当数据来源越来越多时响应速度的变慢就会越明显。为此我们建议您获取数据时采用异步多线程的方式查询,当所有查询任务都完成后合并数据返回即可。

以下是部分实现代码,完整代码请直接点链接查看:TaskApiHandlerImpl.java (opens new window)ApplicationStartUpListener.java (opens new window)TaskApiCallback (opens new window)

/**
 * 任务处理类,提供注册回调的方法以及获取各接口数据的方法
 */
public class TaskApiHandlerImpl implements TaskApiHandler {
    private final static Logger logger = LoggerFactory.getLogger(TaskApiHandlerImpl.class);
    /**
     * 应用中实现类实现了TaskApiCallback,需通过{@link #updateTaskMessage(String)}注册上来
     */
    private final static List<TaskApiCallback> CALLBACK_LIST = Lists.newArrayList();


    /**
     * 并发执行异步线程池,线程数根据实际需求进行配置
     */
    private ExecutorService TASK_API_EXECUTOR;

    public TaskApiHandlerImpl() {
        TASK_API_EXECUTOR = ThreadPoolManager
                .newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 10, ThreadPoolManager.TASK_API_WORKER_NAME, true);
    }

    /**
     * 注册回调
     */
    @Override
    public void registerTaskCallback(TaskApiCallback taskApiCallback) {
        CALLBACK_LIST.add(taskApiCallback);
    }

    /**
     * 获取待办数据
     */
    @Override
    public List<Task> getTodoList(String account) {
        List<Task> todoList = Lists.newArrayList();
        List<CompletableFuture<List<Task>>> futureList = Lists.newArrayList();
        for (TaskApiCallback taskApiCallback : CALLBACK_LIST) {
            //当交我办通过接口请求时,轮询注册的TaskApiCallback,异步轮询回调接口,获取各模块的待办数据
            futureList.add(CompletableFuture.supplyAsync(() -> taskApiCallback.getTodoList(account), TASK_API_EXECUTOR));
        }

        try {
            //合并待办数据
            CompletableFuture.allOf(futureList.toArray(new CompletableFuture[]{})).join();
            for (CompletableFuture<List<Task>> todoFuture : futureList) {
                if (!CollectionUtils.isEmpty(todoFuture.get())) {
                    todoList.addAll(todoFuture.get());
                }
            }
        } catch (Exception e) {
            logger.error("fail to query todo list.", e);
        }

        return todoList;
    }
}

/**
 * 系统启动时注册交我办回调函数
 */
@Component
public class ApplicationStartUpListener  implements ApplicationListener<ContextRefreshedEvent> {

    @Autowired
    private TaskApiHandler taskApiHandler;

    @Resource(name = "taskApiCallBackA")
    private TaskApiCallback taskApiCallbackA;

    @Resource(name = "taskApiCallBackB")
    private TaskApiCallback taskApiCallbackB;

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {

        if(event.getApplicationContext().getParent() == null) {
            /********************************* 交我办待办注册回调函数 *************************************/
            taskApiHandler.registerTaskCallback(taskApiCallbackA);
            taskApiHandler.registerTaskCallback(taskApiCallbackB);
            /********************************* ****************** *************************************/
        }
    }
}

/**
 * 任务回调接口,如果有多类型任务需要查询,实现多个实现该接口的类并注册即可
 */
public interface TaskApiCallback {


    /**
     * 可办任务回调函数
     *
     * @param jaccount 账号
     * @param occupy   岗位信息
     * @return 可办列表
     */
    default List<App> getAppList(String jaccount, String occupy) {
        return Lists.newArrayList();
    }

    /**
     * 待办任务回调函数
     *
     * @param jaccount 帐号
     * @return 待办列表
     */
    default List<Task> getTodoList(String jaccount) {
        return Lists.newArrayList();
    }

    /**
     * 进行中任务回调函数
     * @param account 账号
     * @param start 开始行
     * @param limit 返回行数
     * @param order 排序
     * @param orderTimes 数据时间范围
     * @param keyword 搜索关键字
     * @param sep 是否由别人发起
     * @return 进行中任务列表
     */
    default List<Process> getDoingList(String account, Integer start, Integer limit, String order, String orderTimes, String keyword, Boolean sep) {
        return Lists.newArrayList();
    }

    /**
     * 已完成任务回调函数
     * @param account 账号
     * @param start 开始行
     * @param limit 返回行数
     * @param order 排序
     * @param orderTimes 数据时间范围
     * @param keyword 搜索关键字
     * @param sep 是否由别人发起
     * @return 已完成任务列表
     */
    default List<Process> getDoneList(String account, Integer start, Integer limit, String order, String orderTimes, String keyword, Boolean sep) {
        return Lists.newArrayList();
    }

    /**
     * 已办任务回调函数
     * @param account 账号
     * @param start 开始行
     * @param limit 返回行数
     * @param order 排序
     * @param orderTimes 数据时间范围
     * @param keyword 搜索关键字
     * @param sep 是否由别人发起
     * @return 已办任务列表
     */
    default List<Process> getCompleteList(String account, Integer start, Integer limit, String order, String orderTimes, String keyword, Boolean sep) {
        return Lists.newArrayList();
    }


    /**
     * 已办详情回调函数
     *
     * @param id       任务id
     * @param jaccount 账号
     * @return 任务详情
     */
    default List<Process> getProcessList(String id, String jaccount) {
        return Lists.newArrayList();
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169

# 待办更新

如果有待办接口接入的话,当用户办理待办时需要调用发送任务更新消息来通知交我办刷新该用户的待办列表,接口文档请参考。请注意调用此接口需要为您的应用申请增加客户端模式tasks授权范围。

以下代码给出了一份待办任务更新的实现,其中 API 是交大 api 开发包中的类,可通过 maven 引入。

<dependency>
    <groupId>sjtu</groupId>
    <artifactId>sjtu-api</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>
1
2
3
4
5
public class TaskApiHandlerImpl implements TaskApiHandler {

    @Resource
    private API api;

    private final static Logger logger = LoggerFactory.getLogger(TaskApiHandlerImpl.class);

    private String clientId;

    private String clientSecret;

    public TaskApiHandlerImpl(String clientId, String clientSecret) {
        this.clientId = clientId;
        this.clientSecret = clientSecret;
    }

    @Override
    public void updateTaskMessage(String account) {
        try {
            // 此处还可以优化,通过token是否过期来决定是否需要再获得一个新的token
            OAuthToken token = OAuth2Util.getToken(clientId, clientSecret, "tasks");
            api.postMessage(token.getAccessToken(), account, "task", null);
        } catch (OAuthSystemException | OAuthProblemException e) {
            logger.error("获取token失败", e);
        } catch (APIException e) {
            logger.error("发送任务更新消息失败", e);
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# 页面交互

页面交互有两个地方需要注意

# 多语言

如果您的页面是一个支持多语言的系统,那么所有接口返回的数据中的 uri 链接都要支持多语言。

例如用户在 my 中选择语言为英语,那么调用待办接口时就会带上 locale=en 的参数,我们预期用户希望打开待办链接后显示的就是和 my 选择的语言相同的语言,所以接口返回的待办链接里应该也带上 locale 参数(参数名可以系统自己指定),当用户点了待办链接后您的系统就应该根据链接上的语言参数显示待办页了。

# 待办完成

当用户办理待办完成后,后端应该刷新待办列表,前端应该关闭页面(交我办app中回到办事大厅)。您的前端页面判断当前是在交我办中打开时,应该使用交我办JsSdk调用 close 方法。关于交我办JsSdk的详细介绍请参见此处

import { close } from 'jwb-app-invoker';
// 确认待办完成后调用close方法
close();
1
2
3

# 接口安全

由于任务集成 API 调用应用接口时并没有鉴权参数,所以如果觉得您的接口数据涉及隐私的话可以通过限制 ip 访问的方式来提高安全性,可以联系管理员索要任务集成 API 的服务器地址。

# 测试检查

在接口开发完毕后,您可以联系管理员进行测试检查,我们会将您的接口集成到 my 以及交我办的测试环境中进行测试。测试检查分三部分:数据正确性测试、UI 规范检查、接口性能压测。

# 正确性测试

  • 各接口返回数据可以在 my 和交我办测试环境正常显示
  • 验证各接口是否支持了所有必须的查询参数
  • 待办办理完后是否调用了接口更新待办

# UI 规范检查

  • 查看您的页面是否符合规范要求

# 性能压测

  • 要求各接口在 20-50 线程并发量的情况下,可办、待办接口每秒吞吐量不小于 100,在办、已办、已完成接口每秒吞吐量不小于 50
  • 在连续的压测时间范围内接口不返回错误

# 上线申请

您可以通过交我办应用上线申请 (opens new window)提交接入上线申请,申请通过后我们会按您的需求在指定的时间上线。

# 案例地址

download 代码地址