java 利用mpxj解析MPP及结合jacob导出MPP

server/2024/10/17 21:20:07/

导出mpp需要提前配置

到jacob官网去下载对应的jacob-1.21.zip,获取去jacob github下载,下载后进行解压会有以下文件:

在这里插入图片描述

其中需要将jacob-1.21-x64.dll及jacob-1.21-x86.dll文件放到jdk安装目录下的bin目录下:

在这里插入图片描述
此处便配置好了导出mpp的配置,如需要在Linux环境上配置,也是一样,放到对应的jdk的bin目录下。

pom.xml相关引用

		<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><scope>provided</scope></dependency><!-- hutool工具 --><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.10</version></dependency><!-- mpp文件解析 --><dependency><groupId>net.sf.mpxj</groupId><artifactId>mpxj</artifactId><version>11.2.0</version></dependency><!-- mpp文件导出  说明:这里的jacob是我自己上传到了maven仓库,你可以自己到https://github.com/freemansoft/jacob-project/releases下载对应的zip包解压获取jacob.jar--><dependency><groupId>com.jacob</groupId><artifactId>jacob</artifactId><version>1.21</version></dependency>

Project自定义接收对象

java">import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Project implements Serializable
{private static final long serialVersionUID = -3004215654376730249L;/*** 父级Id */private Integer parentTaskId;/*** 任务序号Id */private Integer taskId;/*** 任务Id (自定义字段)*/private Integer jobId;/** * 任务名称 */private String taskName;/** * 任务类型 (自定义字段)*/private String jobType;/***  工期 */private String duration;/*** 开始时间 */private Date startDate;/*** 完成时间 */private Date finishDate;/*** 资源名称 */private String resource;/*** 在声明时初始化 children 列表*/private List<Project> childrens = new ArrayList<>();public Project(){super();}public Project(Integer parentTaskId, Integer taskId, Integer jobId, String taskName, String jobType,String duration, Date startDate, Date finishDate, Integer preTaskId, String resource){super();this.parentTaskId = parentTaskId;this.taskId = taskId;this.jobId = jobId;this.taskName = taskName;this.jobType = jobType;this.duration = duration;this.startDate = startDate;this.finishDate = finishDate;this.resource = resource;}@Overridepublic String toString(){return "Project [父级ID=" + parentTaskId + ", 任务序号ID=" + taskId + ", 任务ID=" + jobId + ", 任务名称=" + taskName+ ", 任务类型=" + jobType + ", 工期=" + duration + ", 开始时间=" + startDate + ", 结束时间=" + finishDate + ", 资源名称="+ resource + ", 子任务数量=" + childrens.size() + "]";}/*** @Description: 添加子任务* @param child * @return: void*/public void addChild(Project child){this.childrens.add(child);}/*** @Description: 查出任务名称相同的任务名称* @param projects* @return: List<String>*/public static List<String> findDuplicateTaskNames(List<Project> projects){Map<String, Integer> taskNameCount = new HashMap<>();List<String> duplicates = new ArrayList<>();// 遍历任务 统计任务名称出现次数for (Project project : projects){countProjectAndChildrenTaskNames(project, taskNameCount);}// 查出相同任务名称出现次数大于1的for (Map.Entry<String, Integer> entry : taskNameCount.entrySet()){if (entry.getValue() > 1){duplicates.add(entry.getKey());}}return duplicates;}/*** @Description: 统计任务名称出现次数* @param project* @param taskNameCount * @return: void*/private static void countProjectAndChildrenTaskNames(Project project, Map<String, Integer> taskNameCount){// 统计当前任务的任务名称出现次数taskNameCount.put(project.getTaskName(), taskNameCount.getOrDefault(project.getTaskName(), 0) + 1);// 统计当前任务的字任务名称出现次数for (Project child : project.getChildrens()){countProjectAndChildrenTaskNames(child, taskNameCount);}}public Integer getParentTaskId(){return parentTaskId;}public void setParentTaskId(Integer parentTaskId){this.parentTaskId = parentTaskId;}public Integer getTaskId(){return taskId;}public void setTaskId(Integer taskId){this.taskId = taskId;}public Integer getJobId(){return jobId;}public void setJobId(Integer jobId){this.jobId = jobId;}public String getTaskName(){return taskName;}public void setTaskName(String taskName){this.taskName = taskName;}public String getJobType(){return jobType;}public void setJobType(String jobType){this.jobType = jobType;}public String getDuration(){return duration;}public void setDuration(String duration){this.duration = duration;}public Date getStartDate(){return startDate;}public void setStartDate(Date startDate){this.startDate = startDate;}public Date getFinishDate(){return finishDate;}public void setFinishDate(Date finishDate){this.finishDate = finishDate;}public String getResource(){return resource;}public void setResource(String resource){this.resource = resource;}public List<Project> getChildrens(){return childrens;}public void setChildrens(List<Project> childrens){this.childrens = childrens;}}

MPPUtil工具类

java">import java.io.File;
import java.util.ArrayList;
import java.util.List;import com.booway.zentao.fx.biz.vo.mpp.Project;
import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.Dispatch;import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import net.sf.mpxj.CustomField;
import net.sf.mpxj.CustomFieldContainer;
import net.sf.mpxj.Duration;
import net.sf.mpxj.ProjectFile;
import net.sf.mpxj.Resource;
import net.sf.mpxj.ResourceAssignment;
import net.sf.mpxj.Task;
import net.sf.mpxj.TaskField;
import net.sf.mpxj.TaskType;
import net.sf.mpxj.mpp.MPPReader;
import net.sf.mpxj.mspdi.MSPDIWriter;/*** @Description: mpp 工具* @author: wanjun*/
@Slf4j
public class MPPUtil
{/*** @Description: 解析mpp文件* @param filePath* @throws Exception * @return: List<Project>*/public static List<Project> parse(String filePath) throws Exception{List<Project> projectList = new ArrayList<>();MPPReader reader = new MPPReader();ProjectFile mpp = reader.read(new File(filePath));// 遍历所有任务for (Task task : mpp.getTasks()){//            if (task.getID() != null && task.getParentTask() == null) {//                // 如果任务没有父级任务,视为顶级任务//                Project project = createProjectFromTask(task, null);//                projectList.add(project);////                // 处理所有的子任务//                if (task.getChildTasks() != null && !task.getChildTasks().isEmpty()) {//                    project.getChildrens().addAll(parseChildTasks(task.getChildTasks(), project.getTaskId()));//                }//            }// 处理任务id不为0的任务,含子任务if (task.getID() != null && task.getID() != 0 && task.getParentTask() == null){// 顶级任务 (ID 不为 0 的任务)Project project = createProjectFromTask(task, null);projectList.add(project);// 处理所有的子任务if (task.getChildTasks() != null && !task.getChildTasks().isEmpty()){project.getChildrens().addAll(parseChildTasks(task.getChildTasks(), project.getTaskId()));}} else if (task.getID() != null && task.getID() == 0 && task.getParentTask() == null){// 处理任务id为0的任务,含子任务if (task.getChildTasks() != null && !task.getChildTasks().isEmpty()){projectList.addAll(parseChildTasks(task.getChildTasks(), null));}}}return projectList;}/*** 从 Task 对象创建 Project 对象,同时传入父级任务ID*/private static Project createProjectFromTask(Task task, Integer parentTaskId){Project project = new Project();project.setParentTaskId(parentTaskId);project.setTaskId(task.getID());project.setJobId(task.getCachedValue(TaskField.TEXT1) != null? Integer.valueOf(task.getCachedValue(TaskField.TEXT1).toString()): null);project.setTaskName(task.getName());project.setJobType(StrUtil.toStringOrNull(task.getCachedValue(TaskField.TEXT2)));project.setDuration(StrUtil.toStringOrNull(task.getDuration()));project.setStartDate(task.getStart() != null ? DateUtil.date(task.getStart()) : null);project.setFinishDate(task.getFinish() != null ? DateUtil.date(task.getFinish()) : null);// 设置资源List<ResourceAssignment> resourceAssignments = task.getResourceAssignments();if (resourceAssignments != null && !resourceAssignments.isEmpty()){project.setResource(resourceAssignments.get(0).getResource().getName());}return project;}/*** 递归解析子任务列表,并设置每个子任务的 parentTaskId*/private static List<Project> parseChildTasks(List<Task> childTasks, Integer parentTaskId){List<Project> childProjectList = new ArrayList<>();for (Task childTask : childTasks){if (childTask.getID() != null){Project childProject = createProjectFromTask(childTask, parentTaskId);childProjectList.add(childProject);// 递归处理嵌套子任务if (childTask.getChildTasks() != null && !childTask.getChildTasks().isEmpty()){childProject.getChildrens().addAll(parseChildTasks(childTask.getChildTasks(), childProject.getTaskId()));}}}return childProjectList;}/*** @Description: 导出mpp计划* @param projectList* @param mppPath * @return: void*/public static void export(List<Project> projectList, String mppPath){// 【1】Project对象转ProjectFileProjectFile projectFile = convertToMpxjProjectFile(projectList);// 生成临时Mpxj xml文件File tempFile = FileUtil.createTempFile("任务计划", ".xml", true);String xmlPath = tempFile.getAbsolutePath();log.info("生成临时任务计划.xml路径:[{}]", xmlPath);try{MSPDIWriter writer = new MSPDIWriter();writer.write(projectFile, xmlPath);} catch (Exception e){log.error("生成任务计划.xml失败,原因:[{}]", e.getMessage());e.printStackTrace();}// 【2】Mpxj xml文件 转 MPP,前提要安装  Microsoft Projecttry{// 获取MSProject 对象ActiveXComponent activexComponent = new ActiveXComponent("MSProject.Application");// 设置静默打开文件activexComponent.setProperty("Visible", true);// 设置关闭弹窗activexComponent.setProperty("DisplayAlerts", false);// 打开Xml文件Dispatch.call(activexComponent, "FileOpen", xmlPath);// 执行另存为Mpp文件Dispatch.call(activexComponent, "FileSaveAs", mppPath);// 退出Project  不默认打开文件activexComponent.invoke("Quit");} catch (Exception e){log.error("任务计划.xml转MPP文件失败,原因:[{}]", e.getMessage());e.printStackTrace();}}/*** @Description: List<Project>转成ProjectFile* @param projects* @return: ProjectFile*/private static ProjectFile convertToMpxjProjectFile(List<Project> projectList){ProjectFile projectFile = new ProjectFile();// 创建自定义字段 "任务ID" 和 "任务类型"CustomFieldContainer customFields = projectFile.getCustomFields();CustomField customJobIdField = customFields.getOrCreate(TaskField.TEXT1);customJobIdField.setAlias("任务ID");CustomField customJobTypeField = customFields.getOrCreate(TaskField.TEXT2);customJobTypeField.setAlias("任务类型");// 遍历项目列表,将项目转换为任务for (Project project : projectList){// 递归添加任务Task rootTask = projectFile.addTask();addTaskToProject(projectFile, rootTask, project);}return projectFile;}/*** @Description: 递归地将任务和其子任务添加到 ProjectFile* @param projectFile* @param parentTask* @param project * @return: void*/private static void addTaskToProject(ProjectFile projectFile, Task parentTask, Project project){// 设置任务的基本属性parentTask.setName(project.getTaskName());parentTask.setUniqueID(project.getTaskId());parentTask.setID(project.getTaskId());// 设置自定义字段 "任务ID"parentTask.set(TaskField.TEXT1, StrUtil.toStringOrNull(project.getJobId()));parentTask.setName(project.getTaskName());// 设置自定义字段 "任务类型"parentTask.set(TaskField.TEXT2, project.getJobType());// 设置固定工期,否则工期和开始时间、结束时间不正确parentTask.setType(TaskType.FIXED_DURATION);// 需同时设置Start和ActualStartparentTask.setStart(project.getStartDate());parentTask.setActualStart(project.getStartDate());// 处理工期字段 (duration),MPXJ 使用的是 Duration 类if (project.getDuration() != null){try{// 需同时设置Duration和ActualDurationDuration duration = net.sf.mpxj.Duration.getInstance(Double.parseDouble(project.getDuration()),net.sf.mpxj.TimeUnit.DAYS);parentTask.setDuration(duration);parentTask.setActualDuration(duration);} catch (NumberFormatException e){log.error("无法解析工期:[{}]", project.getDuration());}}// 需同时设置Finish和ActualFinishparentTask.setFinish(project.getFinishDate());parentTask.setActualFinish(project.getFinishDate());// 设置资源名称if (project.getResource() != null && !project.getResource().isEmpty()){// 获取或创建资源Resource resource = projectFile.addResource();resource.setName(project.getResource());// 为任务分配资源parentTask.addResourceAssignment(resource);}// 递归添加子任务for (Project child : project.getChildrens()){Task childTask = parentTask.addTask();addTaskToProject(projectFile, childTask, child);}}}

使用示例

java">public static void main(String[] args){try{List<Project> projects = MPPUtil.parse("C:\\Users\\BW\\Desktop\\10月.mpp");// 处理解析后的项目对象...for (Project project : projects){printProject(project, 0);}MPPUtil.export(projects, "C:\\Users\\BW\\Desktop\\新世界计划.mpp");System.out.println("Project MPP file created successfully!");} catch (Exception e){e.printStackTrace();}}// 打印项目任务结构的递归方法private static void printProject(Project project, int level){String indent = "  ".repeat(level);System.out.println(indent + "Project [父级ID=" + project.getParentTaskId() + ", 任务序号ID=" + project.getTaskId()+ ", 任务ID=" + project.getJobId() + ", 任务名称=" + project.getTaskName() + ", 任务类型=" + project.getJobType()+ ", 工期=" + project.getDuration() + ", 开始时间=" + project.getStartDate() + ", 结束时间="+ project.getFinishDate() + ", 资源名称=" + project.getResource() + ", 子任务数量="+ project.getChildrens().size() + "]");for (Project child : project.getChildrens()){printProject(child, level + 1);}}

http://www.ppmy.cn/server/132580.html

相关文章

C、C++常用数据结构:顺序表

前言&#xff1a;线性表 讲顺序表之前先讲讲线性表。 线性表&#xff1a;种数据结构&#xff0c;用来表示具有相同类型的有限个数据元素的集合。线性表的性质&#xff1a; 有序性&#xff1a;线性表中的数据元素是按一定顺序排列的&#xff0c;每个元素都有确定的位置唯一性&…

【论文阅读】OWKRL:2024年的视觉推理任务不用VLMs还可以怎么做

目录 写在前面1. 动机与贡献1.1 动机1.2 贡献 2. 开放世界知识表示学习方法&#xff08;OWKRL&#xff09;2.1 问题定义2.2 知识三元组表示获取2.2.1 基于图的 Self-cross Transformer2.2.2 头实体提取2.2.3 尾实体提取2.2.4 关系提取 2.3 知识表示学习2.3.1 开放世界表示学习2…

github下载文件的两种方式(非git形式)

1.以下面的图为例 &#xff0c;可以直接点击右上方的绿色Code按键&#xff0c;在弹出的列表中选择Download Zip选项&#xff0c;即可下载。 2.如果下载的是单独的某一个文件&#xff0c;则可以按照下图的格式点击下图所示的那个下载的图标即可。

mac安装homebrew和git

简介 由于把自己的新mac拿来撸代码&#xff0c;开始环境搭建&#xff0c;安装各种工具和依赖&#xff0c;安装 git 需要先安装 homebrew&#xff0c;然后就遇到了 homebrew 安装失败的问题。 curl: (7) Failed to connect to raw.githubusercontent.com port 443: Connection…

卸载Python

1、查看安装框架位置并删除 Sudo rm -rf /Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8 2、查看应用并删除 在 /Applications/Python 3.x 看是否存在&#xff0c;如果存在并删除。 3、删除软连接 ls -l /usr/bin/py* 或 ls -…

设备台账管理是什么

设备管理对企业至关重要。比如在电子加工企业&#xff0c;高效的设备管理能减少设备故障&#xff0c;提升生产效率&#xff0c;为企业赢得市场竞争优势。设备台账管理作为设备管理的一个核心部分&#xff0c;起着重要的作用。 让我们一起从本篇文章中探索设备台账管理是什么&a…

Qt网络编程: 构建高效的HTTP文件下载器

文章目录 注意事项调用示例在使用Qt进行HTTP下载时,通常会使用QNetworkAccessManager类来管理HTTP请求和响应。这个类提供了进行网络请求的能力,包括下载文件。下面是使用Qt进行HTTP下载的一个示例,以及在实现时应考虑的一些注意事项。 注意事项 1.错误处理 始终检查QNetwo…

双回路防静电监控仪安全保护生产全流程

在现代工业生产中&#xff0c;静电防护成为了确保安全生产的重要环节&#xff0c;尤其是在电子、化学等易燃易爆气体环境中。静电的存在不仅可能导致设备故障&#xff0c;还可能引发火灾或爆炸等严重事故。为了解决这一隐患&#xff0c;双回路防静电监控仪应运而生&#xff0c;…