审批流程:
第1个环节是“提交申请”,以后基本上都是“审批”环节。
约定:
1,第一个环节一定要是“提交申请”,并且办理人是当前登录的用户。
2,在JBPM中是使用一个字符串作为用户标识符,在ItcastOA中是User对象,不匹配。
可以使用User中一个不会有重复值的字段转为String交给JBPM用。
我们的User可以使用User.id.toString()或User.loginName。
在这里,我们约定使用User.loginName作为JBPM中所用的用户标识符。
3,在提交申请环节生成的信息要求在后面的环节中都能够方便的获取到。
这是使用流程变量实现的。
所有申请的信息都封装到一个application中了,所以只需要设置这个变量,key为"application"。
要求在提交申请的环节就要设置这个变量。
4,第一个环节“提交申请”的办理人应写为:
assignee="#{application.applicant.loginName}"
/**
* 实体:申请模板
*
* @author tyg
*
*/
public class ApplicationTemplate {
private Long id;
private String name;
private String processDefinitionKey;
private String path; // 文件在服务器端存储的路径
/**
* 流转的申请
*
* @author tyg
*
*/
public class Application {
/** 状态常量:审批中 */
public static final String STATUS_RUNNING = "审批中";
/** 状态常量:已通过 */
public static final String STATUS_APPROVED = "已通过";
/** 状态常量:未通过 */
public static final String STATUS_REJECTED = "未通过";
private Long id;
private ApplicationTemplate applicationTemplate;// 所使用的申请模板
private Set<ApproveInfo> approveInfos = new HashSet<ApproveInfo>();//审批的信息
private User applicant;// 申请人
private String title;// 标题
private Date applyTime;// 申请时间
private String path;// 文档的存储路径
private String status; // 当前的状态
/**
* 审批信息
*
* @author tyg
*
*/
public class ApproveInfo {
private Long id;
private Application application; //
private User approver;// 审批人
private Date approveTime;// 审批时间
private boolean approval; // 是否通过
private String comment; // 审批意见
@Controller
@Scope("prototype")
public class ApplicationTemplateAction extends BaseActionWithModelDriven<ApplicationTemplate> {
private File upload; // 上传的文件
private InputStream inputStream; // 下载用的
/** 列表 */
public String list() throws Exception {
List<ApplicationTemplate> applicationTemplateList = applicationTemplateService.findAll();
ActionContext.getContext().put("applicationTemplateList", applicationTemplateList);
return "list";
}
/** 删除,应也同时删除文件 */
public String delete() throws Exception {
applicationTemplateService.delete(model.getId());
return "toList";
}
/** 添加页面 */
public String addUI() throws Exception {
// 准备数据
List<ProcessDefinition> processDefinitionList = processDefinitionService.findAllLatestVersions();
ActionContext.getContext().put("processDefinitionList", processDefinitionList);
return "saveUI";
}
/** 添加 */
public String add() throws Exception {
// 封装
String path = saveUploadFile(upload);
model.setPath(path);
// 保存
applicationTemplateService.save(model);
return "toList";
}
/** 修改页面 */
public String editUI() throws Exception {
// 准备数据
List<ProcessDefinition> processDefinitionList = processDefinitionService.findAllLatestVersions();
ActionContext.getContext().put("processDefinitionList", processDefinitionList);
// 准备回显的数据
ApplicationTemplate applicationTemplate = applicationTemplateService.getById(model.getId());
ActionContext.getContext().getValueStack().push(applicationTemplate);
return "saveUI";
}
/** 修改 */
public String edit() throws Exception {
// 1,从DB中取出原对象
ApplicationTemplate applicationTemplate = applicationTemplateService.getById(model.getId());
// 2,设置要修改的属性
applicationTemplate.setName(model.getName());
applicationTemplate.setProcessDefinitionKey(model.getProcessDefinitionKey());
if (upload != null) { // 如果上传了文件
// 删除老文件
File file = new File(applicationTemplate.getPath());
if (file.exists()) {
file.delete();
}
// 使用新文件
String path = saveUploadFile(upload);
applicationTemplate.setPath(path);
}
// 3,更新到DB
applicationTemplateService.update(applicationTemplate);
return "toList";
}
/** 下载 */
public String download() throws Exception {
// 准备下载的资源
ApplicationTemplate applicationTemplate = applicationTemplateService.getById(model.getId());
inputStream = new FileInputStream(applicationTemplate.getPath());
// 准备文件名(解决乱码问题)
String fileName = URLEncoder.encode(applicationTemplate.getName(), "utf-8"); // 方法一
// String fileName = new String(applicationTemplate.getName().getBytes("gbk"), "iso8859-1"); // 方法二
ActionContext.getContext().put("fileName", fileName);
return "download";
}
// ---
public InputStream getInputStream() {
return inputStream;
}
public void setInputStream(InputStream inputStream) {
this.inputStream = inputStream;
}
public File getUpload() {
return upload;
}
public void setUpload(File upload) {
this.upload = upload;
}
}
@Controller
@Scope("prototype")
public class FlowAction extends BaseAction {
private File upload; // 上传的文件
private Long applicationTemplateId;
private Long applicationId;
private String taskId;
private String comment;
private boolean approval;
private String outcome;
private String applicationStatus;
// ================================== 申请人有关
/** 起草申请(模板列表) */
public String templateList() throws Exception {
List<ApplicationTemplate> applicationTemplateList = applicationTemplateService.findAll();
ActionContext.getContext().put("applicationTemplateList", applicationTemplateList);
return "applicationTemplateList";
}
/** 提交申请页面 */
public String submitUI() throws Exception {
return "submitUI";
}
/** 提交申请 */
public String submit() throws Exception {
// 封装申请信息
Application application = new Application();
application.setApplicant(getCurrentUser()); // 申请人,当前用户
application.setPath(saveUploadFile(upload)); // 保存上传的文件并设置路径
application.setApplicationTemplate(applicationTemplateService.getById(applicationTemplateId));
// 调用业务方法(保存申请信息,并启动流程开始流转)
applicationService.submit(application);
return "toMyApplicationList"; // 成功后转到"我的申请查询"
}
/** 我的申请查询 */
public String myApplicationList() throws Exception {
// 构建查询条件并准备分页信息
new QueryHelper(Application.class, "a")//
.addCondition("a.applicant=?", getCurrentUser())//
.addCondition(applicationTemplateId != null, "a.applicationTemplate.id=?", applicationTemplateId)//
.addCondition(StringUtils.isNotBlank(applicationStatus), "a.status=?", applicationStatus)//
.addOrderProperty("a.applyTime", false)
.preparePageBean(applicationService, pageNum, pageSize);
// 准备数据
List<ApplicationTemplate> applicationTemplateList = applicationTemplateService.findAll();
ActionContext.getContext().put("applicationTemplateList", applicationTemplateList);
return "myApplicationList";
}
// ================================== 审批人有关
/** 待我审批(我的任务列表) */
public String myTaskList() throws Exception {
List<TaskView> taskViewList = applicationService.getMyTaskViewList(getCurrentUser());
ActionContext.getContext().put("taskViewList", taskViewList);
return "myTaskList";
}
/** 审批处理页面 */
public String approveUI() throws Exception {
Set<String> outcomes = applicationService.getOutcomesByTaskId(taskId);
ActionContext.getContext().put("outcomes", outcomes);
return "approveUI";
}
/** 审批处理 */
public String approve() throws Exception {
// 封装
ApproveInfo approveInfo = new ApproveInfo();
approveInfo.setComment(comment);
approveInfo.setApproval(approval);
approveInfo.setApplication(applicationService.getById(applicationId));
approveInfo.setApprover(getCurrentUser()); // 审批人,当前登录用户
approveInfo.setApproveTime(new Date()); // 当前时间
// 调用用业务方法(保存本次审批信息,并办理完任务,并维护申请的状态)
applicationService.approve(approveInfo, taskId, outcome);
return "toMyTaskList"; // 成功后转到待我审批页面
}
/** 查看流转记录 */
public String approveHistory() throws Exception {
Application application = applicationService.getById(applicationId);
ActionContext.getContext().put("approveInfos", application.getApproveInfos());
return "approveHistory";
}
// --------
public File getUpload() {
return upload;
}
public Long getApplicationTemplateId() {
return applicationTemplateId;
}
public void setApplicationTemplateId(Long applicationTemplateId) {
this.applicationTemplateId = applicationTemplateId;
}
public void setUpload(File upload) {
this.upload = upload;
}
public Long getApplicationId() {
return applicationId;
}
public void setApplicationId(Long applicationId) {
this.applicationId = applicationId;
}
public String getTaskId() {
return taskId;
}
public void setTaskId(String taskId) {
this.taskId = taskId;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
public boolean isApproval() {
return approval;
}
public void setApproval(boolean approval) {
this.approval = approval;
}
public String getOutcome() {
return outcome;
}
public void setOutcome(String outcome) {
this.outcome = outcome;
}
public String getApplicationStatus() {
return applicationStatus;
}
public void setApplicationStatus(String applicationStatus) {
this.applicationStatus = applicationStatus;
}
}
@Service
public class ApplicationServiceImpl extends DaoSupportImpl<Application> implements ApplicationService {
@Resource
private ProcessEngine processEngine;
private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
public void submit(Application application) {
// 1,设置属性并保存application
application.setApplyTime(new Date()); // 申请时间,当前时间
application.setStatus(Application.STATUS_RUNNING);
application.setTitle(application.getApplicationTemplate().getName() // 格式为:{模板名称}_{申请人姓名}_{申请时间}
+ "_" + application.getApplicant().getName() //
+ "_" + sdf.format(application.getApplyTime()));
getSession().save(application); // 保存
// 2,启动程程实例开始流转
// >> 准备流程变量
Map<String, Object> variablesMap = new HashMap<String, Object>();
variablesMap.put("application", application);
// >> 启动程程实例,并带上流程变量(当前的申 请信息)
String pdKey = application.getApplicationTemplate().getProcessDefinitionKey();
ProcessInstance pi = processEngine.getExecutionService().startProcessInstanceByKey(pdKey, variablesMap);
// >> 办理完第1个任务“提交申请”
Task task = processEngine.getTaskService()//
.createTaskQuery()// 查询出本流程实例中当前仅有的一个任务“提交申请”
.processInstanceId(pi.getId())//
.uniqueResult();
processEngine.getTaskService().completeTask(task.getId());
}
public List<TaskView> getMyTaskViewList(User currentUser) {
// 查询我的任务列表
String userId = currentUser.getLoginName(); // 约定使用loginName作为JBPM用的用户标识符
List<Task> taskList = processEngine.getTaskService().findPersonalTasks(userId);
// 找出每个任务对应的申请信息
List<TaskView> resultList = new ArrayList<TaskView>();
for (Task task : taskList) {
Application application = (Application) processEngine.getTaskService().getVariable(task.getId(), "application");
resultList.add(new TaskView(task, application));
}
// 返回“任务--申请信息”的结果
return resultList;
}
public void approve(ApproveInfo approveInfo, String taskId, String outcome) {
// 1,保存本次审批信息
getSession().save(approveInfo);
// 2,办理完任务
Task task = processEngine.getTaskService().getTask(taskId); // 一定要先取出Task对象,再完成任务,否则拿不到,因为执行完就变成历史信息了。
if (outcome == null) {
processEngine.getTaskService().completeTask(taskId);
} else {
processEngine.getTaskService().completeTask(taskId, outcome);
}
// >> 取出所属的流程实例,如果取出的为null,说明流程实例执行完成了,已经变成了历史记录
ProcessInstance pi = processEngine.getExecutionService().findProcessInstanceById(task.getExecutionId());
// 3,维护申请的状态
Application application = approveInfo.getApplication();
if (!approveInfo.isApproval()) {
// 如果本环节不同意,则流程实例直接结束,申请的状态为:未通过
if (pi != null) { // 如果流程还未结束
processEngine.getExecutionService().endProcessInstance(task.getExecutionId(), ProcessInstance.STATE_ENDED);
}
application.setStatus(Application.STATUS_REJECTED);
} else {
// 如果本环节同意,而且本环节是最后一个环节,则流程实例正常结束,申请的状态为:已通过
if (pi == null) { // 本环节是最后一个环节,即流程已经结束了
application.setStatus(Application.STATUS_APPROVED);
}
}
getSession().update(application);
}
public Set<String> getOutcomesByTaskId(String taskId) {
// 获取指定任务活动中所有流出的连线名称
return processEngine.getTaskService().getOutcomes(taskId);
}
}