在前两章我们实现了线上和线下会议申请功能,那么所有的会议申请都要在审批任务页面显示出来,然后由相关的人员执行审批工作。在审批任务页面(approval.vue),我们可以看到这个会议申请。相关人员点开这个会议申请记录,可以看到详细的申请信息,甚至说现在审批工作执行到了工作流程的哪一个步骤,都显示的清清楚楚。
这里有个细节问题,大家需要注意。那就是审批详情信息要不要随着分页记录一起查询出来?当然是不需要的,因为审批人不一定会点开每个审批记录,然而你却把每个会议申请的详情信息都查询出来,白白增大了数据库的负担。正确的做法是用户点开申请记录的时候,再发送Ajax请求查询审批详情信息。而且Ajax必须是同步执行的,这是因为如果Ajax选择了异步执行,展开申请记录的JS回调函数不会等着Ajax执行完,导致JS回调函数执行结束,强制让Ajax也结束了。这绝对是不行的,所以我们要选择同步方式的Ajax请求。
一、查询工作流分页数据Web接口
因为审批任务页面是为用户提供审批服务的,所以页面中各种申请记录对应的都是工作流实例,我们只需要调用工作流项目就能获取到分页记录了。
接口URI:/workflow/searchTaskByPage
序号 | 参数名 | 类型 | 必填 | 说明 |
---|---|---|---|---|
1 | userId | int | 是 | 用户ID |
2 | role | String[] | 是 | 角色列表 |
3 | page | int | 是 | 页数 |
4 | length | int | 是 | 每页记录数量 |
5 | type | String | 否 | 员工请假 |
6 | status | String | 是 | 待审批 |
7 | creatorName | String | 否 | 申请人 |
8 | instanceId | String | 否 | 工作流实例ID |
9 | code | String | 是 | 慕课网授权码 |
10 | tcode | String | 是 | 课程授权码 |
大家请看下面的时序图,发送HTTP请求调用工作流项目Web接口,是由ApprovalServiceImpl
类做的,而不是交给异步线程任务类去做。这是因为我们必须要从工作流项目查询出来数据,然后返回给前端页面,这个过程必须是同步。如果采用异步,数据还没查询出来,Controller直接返回R对象了,这可绝对不行。
二、编写持久层代码
在TbUserDao.xml
文件中,定义查询用户角色的SQL语句。
<select id="searchUserRoles" parameterType="int" resultType="String">
SELECT
r.role_name AS roleName
FROM
tb_user u
JOIN tb_role r ON JSON_CONTAINS ( u.role, CONVERT ( r.id, CHAR ) )
WHERE u.id=#{userId}
</select>
在TbUserDao.java
接口中,声明DAO方法。
public interface TbUserDao {
……
public ArrayList<String> searchUserRoles(int userId);
}
三、编写业务层代码
在UserService.java
接口中,声明抽象方法。
public interface UserService {
……
public ArrayList<String> searchUserRoles(int userId);
}
在UserServiceImpl.java
类中,实现抽象方法。
public class UserServiceImpl implements UserService {
……
@Override
public ArrayList<String> searchUserRoles(int userId) {
ArrayList<String> list = userDao.searchUserRoles(userId);
return list;
}
}
创建ApprovalService.java
接口,声明抽象方法。
public interface ApprovalService {
public PageUtils searchTaskByPage(HashMap param);
}
创建ApprovalServiceImpl.java
类,实现抽象方法。
@Service
@Slf4j
public class ApprovalServiceImpl implements ApprovalService {
@Value("${workflow.url}")
private String workflow;
@Value("${emos.code}")
private String code;
@Value("${emos.tcode}")
private String tcode;
@Override
public PageUtils searchTaskByPage(HashMap param) {
param.put("code", code);
param.put("tcode", tcode);
String url = workflow + "/workflow/searchTaskByPage";
HttpResponse resp = HttpRequest.post(url).header("Content-Type", "application/json")
.body(JSONUtil.toJsonStr(param)).execute();
if (resp.getStatus() == 200) {
JSONObject json = JSONUtil.parseObj(resp.body());
JSONObject page = json.getJSONObject("page");
ArrayList list = page.get("list", ArrayList.class);
Long totalCount = page.getLong("totalCount");
Integer pageIndex = page.getInt("pageIndex");
Integer pageSize = page.getInt("pageSize");
PageUtils pageUtils = new PageUtils(list, totalCount, pageIndex, pageSize);
return pageUtils;
} else {
log.error(resp.body());
throw new EmosException("获取工作流数据异常");
}
}
}
在业务层的代码中,我们定义变量接收值注入信息,其中有一个关键点,稍不注意就会引发错误。那就是tcode状态码的注入。我们在application.yml文件中,定义tcode的时候必须要加双引号。
如果不加双引号,SpringBoot会把001234当成是8进制的数字,然后转换成10进制数字,再转换成字符串注入给tcode变量,于是我们得到的注入值为668。但是你加上双引号,就不会有这个问题,大家切记!
四、编写Web层代码
创建SearchTaskByPageForm.java
类,用于封装Ajax提交的数据。
@Data
@Schema(description = "查询任务分页列表表单")
public class SearchTaskByPageForm {
@Pattern(regexp = "^[\\e4e00-\\u9fa5]{2,20}$", message = "creatorName内容不正确")
private String creatorName;
@Pattern(regexp = "^员工请假$|^会议申请$", message = "type内容不正确")
private String type;
@Pattern(regexp = "^[0-9a-zA-Z\\-]{36}$", message = "instanceId内容不正确")
private String instanceId;
@NotBlank(message = "status不能为空")
@Pattern(regexp = "^待审批$|^已审批$|^已结束$", message = "status内容不正确")
private String status;
@NotNull(message = "page不能为空")
@Min(value = 1, message = "page不能小于1")
private Integer page;
@NotNull(message = "length不能为空")
@Range(min = 10, max = 100, message = "length必须在10~100之间")
private Integer length;
}
创建ApprovalController.java
类,定义Web方法。
@RestController
@RequestMapping("/approval")
@Tag(name = "ApprovalController", description = "任务审批Web接口")
@Slf4j
public class ApprovalController {
@Value("${workflow.url}")
private String workflow;
@Value("${emos.code}")
private String code;
@Value("${emos.tcode}")
private String tcode;
@Autowired
private ApprovalService approvalService;
@Autowired
private UserService userService;
@PostMapping("/searchTaskByPage")
@Operation(summary = "查询分页任务列表")
@SaCheckPermission(value = {"WORKFLOW:APPROVAL", "FILE:ARCHIVE"}, mode = SaMode.OR)
public R searchTaskByPage(@Valid @RequestBody SearchTaskByPageForm form) {
HashMap param = JSONUtil.parse(form).toBean(HashMap.class);
int userId = StpUtil.getLoginIdAsInt();
param.put("userId", userId);
param.put("role", userService.searchUserRoles(userId));
PageUtils pageUtils = approvalService.searchTaskByPage(param);
return R.ok().put("page", pageUtils);
}
}
用Swagger测试Web方法的时候,要启动工作流项目。