自学内容网 自学内容网

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)!