java 利用mpxj解析MPP及结合jacob导出MPP
导出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自定义接收对象
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;
}
@Override
public 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工具类
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对象转ProjectFile
ProjectFile 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 Project
try
{
// 获取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和ActualStart
parentTask.setStart(project.getStartDate());
parentTask.setActualStart(project.getStartDate());
// 处理工期字段 (duration),MPXJ 使用的是 Duration 类
if (project.getDuration() != null)
{
try
{
// 需同时设置Duration和ActualDuration
Duration 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和ActualFinish
parentTask.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);
}
}
}
使用示例
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);
}
}
原文地址:https://blog.csdn.net/Chioce/article/details/142985338
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!