浏览代码

生成预审申请单pdf

master
CMM 1年前
父节点
当前提交
d47099019a
共有 18 个文件被更改,包括 482 次插入467 次删除
  1. +6
    -0
      pmapi/pom.xml
  2. +22
    -22
      pmapi/src/main/java/com/ningdatech/pmapi/irs/sign/IRSAPIRequest.java
  3. +44
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/projectlib/enumeration/FourSystemEnum.java
  4. +1
    -1
      pmapi/src/main/java/com/ningdatech/pmapi/projectlib/handle/PreliminaryPreviewHandle.java
  5. +3
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/projectlib/model/entity/Project.java
  6. +6
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/todocenter/controller/TodoCenterController.java
  7. +71
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/todocenter/enumeration/IsOrNotEnum.java
  8. +230
    -17
      pmapi/src/main/java/com/ningdatech/pmapi/todocenter/manage/TodoCenterManage.java
  9. +6
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/todocenter/model/dto/PdfGenerateDTO.java
  10. +24
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/todocenter/model/dto/SignReqDTO.java
  11. +0
    -140
      pmapi/src/main/java/com/ningdatech/pmapi/todocenter/utils/PdfGenerateUtil.java
  12. +10
    -14
      pmapi/src/main/java/com/ningdatech/pmapi/todocenter/utils/PdfUtils.java
  13. 二进制
      pmapi/src/main/resources/template/fileout/c34f631755a04532a0116494fd5f99ac.pdf
  14. +0
    -254
      pmapi/src/main/resources/template/盖章文件.html
  15. +47
    -10
      pmapi/src/main/resources/template/预审申请单.html
  16. 二进制
      pmapi/src/main/resources/template/预审申请单.pdf
  17. +6
    -9
      pmapi/src/test/java/com/ningdatech/pmapi/todocenter/TodoCenterTest.java
  18. +6
    -0
      pom.xml

+ 6
- 0
pmapi/pom.xml 查看文件

@@ -247,6 +247,12 @@
<groupId>org.xhtmlrenderer</groupId>
<artifactId>flying-saucer-pdf-itext5</artifactId>
</dependency>
<!--将html转换成pdf-->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>html2pdf</artifactId>
</dependency>


</dependencies>
<!-- 打包 -->


+ 22
- 22
pmapi/src/main/java/com/ningdatech/pmapi/irs/sign/IRSAPIRequest.java 查看文件

@@ -1,7 +1,7 @@
package com.ningdatech.pmapi.irs.sign;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ningdatech.pmapi.todocenter.model.dto.SignReqDTO;
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.http.HttpEntity;
@@ -28,7 +28,6 @@ import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;


public class IRSAPIRequest {
//天印服务器接口信息
// private static String ProjectID = "XXX";
@@ -43,11 +42,8 @@ public class IRSAPIRequest {
private static String secretKey = "XXXX";
private static String apiUrl = "https://ibcdsg.zj.gov.cn:8443/restapi/prod/IC33000020220309000004/seal-platform/seal/v1/rest/sign/signPdf";


public static void main(String[] args) throws Exception {

createSignPdf();

}

/**
@@ -56,33 +52,36 @@ public class IRSAPIRequest {
*
* @return
*/
public static JSONObject createSignPdf() {
public static byte[] createSignPdf(SignReqDTO req) {
String pdfEncode64 = req.getPdfEncode64();
Float posX = req.getPosX();
Float posY = req.getPosY();
String sealSn = req.getSealSn();
String fileName = req.getFileName();
JSONObject obj = null;
String resp = null;
try {
JSONObject ReqData = new JSONObject();
String pathname = "D://001.pdf";
File file = new File(pathname);
String fileByte1 = IRSAPIRequest.PDFToBase64(file);
ReqData.put("fileBase64", fileByte1);
ReqData.put("sealSn", "33012108041829053952");
ReqData.put("posX", "200");
ReqData.put("posY", "200");
ReqData.put("fileBase64", pdfEncode64);
ReqData.put("sealSn", sealSn);
ReqData.put("posX", posX);
ReqData.put("posY", posY);
ReqData.put("signType", "1");
// ReqData.put("key", "单位");
ReqData.put("posPage", "1");
ReqData.put("fileName", "01.pdf");

ReqData.put("fileName", fileName);
resp = post(ReqData, "post");
JSONObject jsonObject = JSON.parseObject(resp);
String data = jsonObject.getString("data");
JSONObject jsondata = JSON.parseObject(data);
String signFileB64 = jsondata.getString("signFileB64");
IRSAPIRequest.base64StringToPdf(signFileB64, "D:\\test21.pdf");

//JSONObject jsonObject = JSON.parseObject(resp);
//String data = jsonObject.getString("data");
//JSONObject jsondata = JSON.parseObject(data);
//String signFileB64 = jsondata.getString("signFileB64");
//IRSAPIRequest.base64StringToPdf(signFileB64, "D:\\test21.pdf");
} catch (Exception e) {
e.printStackTrace();
}
return obj;
// return obj;
return resp.getBytes();
}


@@ -275,7 +274,8 @@ public class IRSAPIRequest {
BufferedOutputStream bos = null;

try {
byte[] bytes = decoder.decodeBuffer(base64Content);//base64编码内容转换为字节数组
// base64编码内容转换为字节数组
byte[] bytes = decoder.decodeBuffer(base64Content);
ByteArrayInputStream byteInputStream = new ByteArrayInputStream(bytes);
bis = new BufferedInputStream(byteInputStream);
File file = new File(filePath);


+ 44
- 0
pmapi/src/main/java/com/ningdatech/pmapi/projectlib/enumeration/FourSystemEnum.java 查看文件

@@ -0,0 +1,44 @@
package com.ningdatech.pmapi.projectlib.enumeration;

import java.util.Objects;

import org.apache.commons.lang3.StringUtils;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

/**
* 四大体系枚举
*
* @return
* @author CMM
* @since 2023/03/16 16:27
*/
@Getter
@AllArgsConstructor
@NoArgsConstructor
public enum FourSystemEnum {
/**
* 项目类型
*/
BUSINESS_APPLICATION(1, "业务应用"),
APPLICATION_SUPPORT(2, "应用支撑"),
DATA_RESOURCES(3, "数据资源"),
INFRASTRUCTURE(4, "基础设施");

private Integer code;
private String desc;

public static String getDescByCode(Integer code) {
if (Objects.isNull(code)) {
return StringUtils.EMPTY;
}
for (FourSystemEnum t : FourSystemEnum.values()) {
if (code.equals(t.getCode())) {
return t.desc;
}
}
return StringUtils.EMPTY;
}
}

+ 1
- 1
pmapi/src/main/java/com/ningdatech/pmapi/projectlib/handle/PreliminaryPreviewHandle.java 查看文件

@@ -47,7 +47,7 @@ public class PreliminaryPreviewHandle extends AbstractProcessBusinessHandle {
// 根据项目ID查询项目预审流程的流程状态
ProjectInst projectInst = projectInstService.getOne(Wrappers.lambdaQuery(ProjectInst.class)
.eq(ProjectInst::getProjectId, projectId)
.eq(ProjectInst::getInstType, InstTypeEnum.DEPT_UNITED_REVIEW.getCode())
.eq(ProjectInst::getInstType, InstTypeEnum.PRELIMINARY_PREVIEW.getCode())
.orderByDesc(ProjectInst::getCreatOn)
.last("limit 1"));
if (Objects.isNull(projectInst)){


+ 3
- 0
pmapi/src/main/java/com/ningdatech/pmapi/projectlib/model/entity/Project.java 查看文件

@@ -312,4 +312,7 @@ public class Project implements Serializable {
@ApiModelProperty("项目预审申请单文件ID")
private Long pretrialFileId;

@ApiModelProperty("项目预审申请单文件名")
private String pretrialFileName;

}

+ 6
- 0
pmapi/src/main/java/com/ningdatech/pmapi/todocenter/controller/TodoCenterController.java 查看文件

@@ -169,4 +169,10 @@ public class TodoCenterController {
String instanceId = todoCenterManage.adjustmentAndHandle(dto);
return "退回项目内容调整并且重新通过 【" + instanceId + "】 成功";
}

@ApiOperation("获取未签章的pdf文件")
@PostMapping("/getNotSealedPdf/{projectId}")
public Long getNotSealedPdf (@Valid @PathVariable("projectId") Long projectId){
return todoCenterManage.getNotSealedPdf(projectId);
}
}

+ 71
- 0
pmapi/src/main/java/com/ningdatech/pmapi/todocenter/enumeration/IsOrNotEnum.java 查看文件

@@ -0,0 +1,71 @@
package com.ningdatech.pmapi.todocenter.enumeration;

import java.util.Objects;

import org.apache.commons.lang3.StringUtils;

import io.swagger.annotations.ApiModel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

/**
* 是否增补项目枚举
*
* @author CMM
*/
@Getter
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(value = "IsOrNotEnum", description = "是否-枚举")
public enum IsOrNotEnum {
/**
* 否
*/
NOT(0, "否"),

/**
* 是
*/
IS(1, "是");


private Integer code;
private String desc;

public String getDesc() {
return desc;
}

public void setDesc(String desc) {
this.desc = desc;
}

public static String getDescByCode(Integer code) {
if (Objects.isNull(code)) {
return StringUtils.EMPTY;
}
for (IsOrNotEnum t : IsOrNotEnum.values()) {
if (code.equals(t.getCode())) {
return t.desc;
}
}
return StringUtils.EMPTY;
}

public static IsOrNotEnum getEnumByValue(Integer code) {
if (Objects.isNull(code)) {
return null;
}
for (IsOrNotEnum t : IsOrNotEnum.values()) {
if (code.equals(t.getCode())) {
return t;
}
}
return null;
}

public boolean eq(String val) {
return this.name().equals(val);
}
}

+ 230
- 17
pmapi/src/main/java/com/ningdatech/pmapi/todocenter/manage/TodoCenterManage.java 查看文件

@@ -1,40 +1,53 @@
package com.ningdatech.pmapi.todocenter.manage;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Sets;
import com.ningdatech.basic.exception.BizException;
import com.ningdatech.basic.function.VUtils;
import com.ningdatech.basic.model.PageVo;
import com.ningdatech.basic.util.CollUtils;
import com.ningdatech.basic.util.NdDateUtils;
import com.ningdatech.file.entity.File;
import com.ningdatech.file.entity.vo.result.FileResultVO;
import com.ningdatech.file.service.FileService;
import com.ningdatech.pmapi.common.constant.CommonConst;
import com.ningdatech.pmapi.common.helper.UserInfoHelper;
import com.ningdatech.pmapi.common.model.entity.ExcelExportWriter;
import com.ningdatech.pmapi.common.statemachine.event.ProjectStatusChangeEvent;
import com.ningdatech.pmapi.common.statemachine.util.StateMachineUtils;
import com.ningdatech.pmapi.common.util.ExcelDownUtil;
import com.ningdatech.pmapi.irs.sign.IRSAPIRequest;
import com.ningdatech.pmapi.organization.model.entity.DingEmployeeInfo;
import com.ningdatech.pmapi.organization.model.entity.DingOrganization;
import com.ningdatech.pmapi.organization.service.IDingEmployeeInfoService;
import com.ningdatech.pmapi.organization.service.IDingOrganizationService;
import com.ningdatech.pmapi.projectdeclared.manage.DefaultDeclaredProjectManage;
import com.ningdatech.pmapi.projectdeclared.model.dto.DefaultDeclaredDTO;
import com.ningdatech.pmapi.projectlib.enumeration.FourSystemEnum;
import com.ningdatech.pmapi.projectlib.enumeration.InstTypeEnum;
import com.ningdatech.pmapi.projectlib.enumeration.ProjectStatusEnum;
import com.ningdatech.pmapi.projectlib.enumeration.ProjectTypeEnum;
import com.ningdatech.pmapi.projectlib.manage.ProjectLibManage;
import com.ningdatech.pmapi.projectlib.model.dto.ProjectDTO;
import com.ningdatech.pmapi.projectlib.model.entity.Project;
import com.ningdatech.pmapi.projectlib.model.entity.ProjectApplication;
import com.ningdatech.pmapi.projectlib.model.entity.ProjectInst;
import com.ningdatech.pmapi.projectlib.model.req.ProjectListReq;
import com.ningdatech.pmapi.projectlib.model.vo.ProjectLibListItemVO;
import com.ningdatech.pmapi.projectlib.service.IProjectApplicationService;
import com.ningdatech.pmapi.projectlib.service.IProjectInstService;
import com.ningdatech.pmapi.projectlib.service.IProjectService;
import com.ningdatech.pmapi.signature.entity.CompanySignature;
import com.ningdatech.pmapi.signature.service.ICompanySignatureService;
import com.ningdatech.pmapi.staging.enums.MsgTypeEnum;
import com.ningdatech.pmapi.staging.service.INdWorkNoticeStagingService;
import com.ningdatech.pmapi.staging.service.IProjectStagingService;
import com.ningdatech.pmapi.todocenter.bean.entity.WorkNoticeInfo;
import com.ningdatech.pmapi.todocenter.enumeration.IsOrNotEnum;
import com.ningdatech.pmapi.todocenter.model.dto.AdjustHandleDTO;
import com.ningdatech.pmapi.todocenter.model.dto.PdfGenerateDTO;
import com.ningdatech.pmapi.todocenter.model.dto.SignReqDTO;
import com.ningdatech.pmapi.todocenter.model.vo.ProcessProgressDetailVo;
import com.ningdatech.pmapi.todocenter.enumeration.IsAppendProjectEnum;
import com.ningdatech.pmapi.todocenter.model.req.ProcessDetailReq;
@@ -42,6 +55,7 @@ import com.ningdatech.pmapi.todocenter.model.req.ToBeProcessedExportReq;
import com.ningdatech.pmapi.todocenter.model.req.ToBeProcessedReq;
import com.ningdatech.pmapi.todocenter.model.vo.ResToBeProcessedVO;
import com.ningdatech.pmapi.todocenter.utils.BuildUserUtils;
import com.ningdatech.pmapi.todocenter.utils.PdfUtils;
import com.ningdatech.pmapi.user.entity.UserInfo;
import com.ningdatech.pmapi.user.security.auth.model.UserFullInfoDTO;
import com.ningdatech.pmapi.user.service.IUserInfoService;
@@ -50,33 +64,36 @@ import com.wflow.contants.HisProInsEndActId;
import com.wflow.exception.BusinessException;
import com.wflow.workflow.bean.dto.ProcessInstanceUserDto;
import com.wflow.workflow.bean.dto.ReqProcessHandlerDTO;
import com.wflow.workflow.bean.process.ProcessComment;
import com.wflow.workflow.bean.dto.SealPositionInfoDTO;
import com.wflow.workflow.bean.process.ProgressNode;
import com.wflow.workflow.bean.process.enums.NodeTypeEnum;
import com.wflow.workflow.bean.vo.ProcessInstanceVo;
import com.wflow.workflow.bean.vo.ProcessProgressVo;
import com.wflow.workflow.bean.vo.ProcessTaskVo;
import com.wflow.workflow.enums.ProcessHandlerEnum;
import com.wflow.workflow.enums.ProcessStatusEnum;
import com.wflow.workflow.service.ProcessInstanceService;
import com.wflow.workflow.service.ProcessTaskService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.assertj.core.util.Lists;
import org.flowable.bpmn.model.*;
import org.flowable.engine.HistoryService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.runtime.ActivityInstance;
import org.mockito.internal.matchers.CompareTo;
import org.springframework.beans.BeanUtils;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.URL;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.ningdatech.pmapi.todocenter.constant.WorkNotice.*;
import static com.wflow.workflow.task.TriggerServiceTask.runtimeService;

@@ -93,10 +110,8 @@ public class TodoCenterManage {
private final HistoryService historyService;
private final IUserInfoService userInfoService;
private final IProjectService projectService;

private final ProjectLibManage projectLibManage;
private final StateMachineUtils stateMachineUtils;

private final IDingEmployeeInfoService dingEmployeeInfoService;
private final IDingOrganizationService dingOrganizationService;
private final ProcessInstanceService processInstanceService;
@@ -105,8 +120,11 @@ public class TodoCenterManage {
private final IProjectApplicationService projectApplicationService;
private final UserInfoHelper userInfoHelper;
private final BuildUserUtils buildUserUtils;

private final IProjectStagingService projectStagingService;
private final IProjectInstService projectInstService;
private final PdfUtils pdfUtils;
private final FileService fileService;
private final ICompanySignatureService companySignatureService;


/**
@@ -246,8 +264,14 @@ public class TodoCenterManage {
switch (param.getAction()) {
// 通过
case PASS:
// 盖章并通过
case SEAL_PASS:
// 通过该任务,流程到下一审核人处
processTaskService.handleTask(param, userId);
if (ProcessHandlerEnum.SEAL_PASS.name().equals(param.getAction().name())) {
// 调用IRS接口,获取盖章后的pdf文件,并保存到项目库中
getSignPdf(param, declaredProject);
}
// 获取流程通过后的流程实例
HistoricProcessInstance newInstance = historyService.createHistoricProcessInstanceQuery()
.processInstanceId(processInstanceId)
@@ -313,12 +337,6 @@ public class TodoCenterManage {
workNoticeStagingService.addByWorkNotice(sendWorkNoticeInfo, MsgTypeEnum.AUDIT);
}
break;
// 盖章并通过
case SEAL_PASS:
// TODO 调用盖章接口,返回盖章后的文件流
// 通过该任务,流程到下一审核人处
processTaskService.handleTask(param, userId);
break;
// 驳回
case REJECT:
// 驳回该任务,中止流程并使项目进入对应状态,给项目创建人、流程发起人发送浙政钉工作通知:
@@ -406,6 +424,63 @@ public class TodoCenterManage {
}
}

/**
* 调用IRS接口,获取盖章后的pdf文件,上传到OSS,并保存文件ID到项目库中
* @param param
* @param declaredProject
* @return void
* @author CMM
* @since 2023/03/16 21:34
*/
private void getSignPdf(ReqProcessHandlerDTO param, Project declaredProject) {
Long projectId = param.getProjectId();
// 设置pdf模板参数
JSONObject paramsMap = assemblyPdfParams(projectId);
// TODO 根据当前盖章单位设置对应的盖章意见与盖章日期
paramsMap.put("superOrgOpinion",null);
paramsMap.put("superOrgAuditDate",null);
paramsMap.put("higherOrgOpinion",null);
paramsMap.put("higherOrgAuditDate",null);
paramsMap.put("bigDataBureauOpinion",null);
paramsMap.put("bigDataBureauAuditDate",null);
// 再次获取装配了盖章意见和盖章日期参数的未盖章pdf文件
Long pretrialFileId = generateNotSealedPdf(projectId,paramsMap);
// 获取预审申请单文件,并转换为Base64
File pdfFile = fileService.getById(pretrialFileId);
InputStream fileInputStream = fileService.getFileInputStream(pdfFile);
String pdfEncode64 = Base64.encode(fileInputStream);
// 装配盖章接口请求参数信息
SignReqDTO req = new SignReqDTO();
req.setPdfEncode64(pdfEncode64);
String originalFileName = pdfFile.getOriginalFileName();
req.setFileName(originalFileName);
SealPositionInfoDTO sealPositionInfo = param.getSealInfo();
Float posX = sealPositionInfo.getPosX();
Float posY = sealPositionInfo.getPosY();
req.setPosX(posX);
req.setPosY(posY);
// 获取流程发起人信息
Long projectSponsor = declaredProject.getSponsor();
UserFullInfoDTO userFullInfo = userInfoHelper.getUserFullInfo(projectSponsor);
// 获取印章编号
CompanySignature companySignature = companySignatureService.getOne(Wrappers.lambdaQuery(CompanySignature.class)
.eq(CompanySignature::getOrganizationCode, userFullInfo.getOrganizationCode()));
String sealSn = companySignature.getSealSn();
req.setSealSn(sealSn);

// 调用盖章接口,获取盖章后返回的pdf文件字符数组
byte[] signPdf = IRSAPIRequest.createSignPdf(req);
// 转换成MultipartFile
MultipartFile multipartFile = new MockMultipartFile("file", originalFileName + ".pdf", "application/pdf", signPdf);
// 上传OSS
FileResultVO resultVo = fileService.upload(multipartFile, "default");
// 将返回的文件ID更新到项目库中对应的项目下
declaredProject.setPretrialFileId(resultVo.getId());
declaredProject.setPretrialFileName(resultVo.getOriginalFileName());
declaredProject.setUpdateOn(LocalDateTime.now());
projectService.updateById(declaredProject);
}


/**
* 当为驳回操作时,更新项目表中的项目状态
@@ -938,4 +1013,142 @@ public class TodoCenterManage {
}
return Boolean.TRUE;
}

/**
* 获取未盖章的预审申请单pdf文件
* @param projectId
* @return java.lang.Long
* @author CMM
* @since 2023/03/16 22:46
*/
public Long getNotSealedPdf(Long projectId) {
// 设置pdf模板参数
JSONObject paramsMap = assemblyPdfParams(projectId);
paramsMap.put("superOrgOpinion",null);
paramsMap.put("superOrgAuditDate",null);
paramsMap.put("higherOrgOpinion",null);
paramsMap.put("higherOrgAuditDate",null);
paramsMap.put("bigDataBureauOpinion",null);
paramsMap.put("bigDataBureauAuditDate",null);
return generateNotSealedPdf(projectId, paramsMap);
}

private Long generateNotSealedPdf(Long projectId, JSONObject paramsMap) {
// 获取本地目录的pdf模板
String fileName = "预审申请单";
InputStream htmlInputStream =
this.getClass().getClassLoader().getResourceAsStream("template/" + fileName + ".html");
// 生成pdf字节数组
byte[] pdf = pdfUtils.generatePdf(htmlInputStream, paramsMap);

// 转换成MultipartFile
MultipartFile multipartFile = new MockMultipartFile("file", fileName + ".pdf", "application/pdf", pdf);

// 上传OSS
FileResultVO resultVO = fileService.upload(multipartFile, "default");

// 将返回的文件ID保存到项目库中
Project project = projectService.getById(projectId);
project.setPretrialFileId(resultVO.getId());
project.setPretrialFileName(resultVO.getOriginalFileName());
project.setUpdateOn(LocalDateTime.now());
projectService.updateById(project);


try {
if (null != htmlInputStream) {
htmlInputStream.close();
}

// 删除输出文件夹下的临时文件
java.io.File resourcesPath = new java.io.File("pmapi/src/main/resources");
String reportPath = resourcesPath.getCanonicalPath();
String path = reportPath + "/template/fileout";
java.io.File directory = new java.io.File(path);
FileUtils.cleanDirectory(directory);
} catch (IOException e) {
log.error(e.getMessage());
}

// 返回文件id供前端下载
return resultVO.getId();
}

/**
* 装配pdf模板参数
* @param projectId 申报项目ID
* @return com.alibaba.fastjson.JSONObject
* @author CMM
* @since 2023/03/16 22:28
*/
private JSONObject assemblyPdfParams(Long projectId) {
// 获取本地目录的pdf模板
String fileName = "预审申请单";
// 获取表单数据
Project project = projectService.getById(projectId);
PdfGenerateDTO pdfGenerateDTO = new PdfGenerateDTO();
BeanUtils.copyProperties(project, pdfGenerateDTO);
JSONObject paramsMap = JSONObject.parseObject(JSONObject.toJSONString(pdfGenerateDTO));
// 设置title
String title = "【" + project.getProjectName() + "】" + fileName;
paramsMap.put("title",title);
// 获取流程发起人信息
Long projectSponsor = project.getSponsor();
UserFullInfoDTO userFullInfo = userInfoHelper.getUserFullInfo(projectSponsor);
// 获取印章编号
CompanySignature companySignature = companySignatureService.getOne(Wrappers.lambdaQuery(CompanySignature.class)
.eq(CompanySignature::getOrganizationCode, userFullInfo.getOrganizationCode()));
if (Objects.nonNull(companySignature)){
String sealSn = companySignature.getSealSn();
paramsMap.put("projectNo", sealSn);
}else {
paramsMap.put("projectNo", null);
}
// 获取预审申报的开始时间
ProjectInst projectInst = projectInstService.getOne(Wrappers.lambdaQuery(ProjectInst.class)
.eq(ProjectInst::getProjectId, projectId)
.eq(ProjectInst::getInstType, InstTypeEnum.PRELIMINARY_PREVIEW.getCode())
.orderByDesc(ProjectInst::getCreatOn)
.last("limit 1"));
LocalDateTime time = null;
if (Objects.nonNull(projectInst)) {
time = projectInst.getCreatOn();
paramsMap.put("time", NdDateUtils.format(time, "yyyy-MM-dd HH:mm"));
}else {
paramsMap.put("time", null);
}
// 获取是否临时增补项目
String isTemporaryAugment = IsOrNotEnum.getDescByCode(project.getIsTemporaryAugment());
paramsMap.put("isTemporaryAugment", isTemporaryAugment);
// 获取项目类型
Integer projectType = project.getProjectType();
paramsMap.put("projectType", ProjectTypeEnum.getDesc(projectType));
// 获取是否首次新建
String isFirst = IsOrNotEnum.getDescByCode(project.getIsFirst());
paramsMap.put("isFirst", isFirst);
// 获取是否一地创新全省共享项目
Boolean isInnovateWholeProvinceShare = project.getIsInnovateWholeProvinceShare();
paramsMap.put("isInnovateWholeProvinceShare", Boolean.TRUE.equals(isInnovateWholeProvinceShare) ?
IsOrNotEnum.IS.getDesc() : IsOrNotEnum.NOT.getDesc());
// 获取项目建设起始时间
String beginTime = project.getBeginTime();
String endTime = project.getEndTime();
String beginAndEndTime = beginTime + StrUtil.DASHED + endTime;
paramsMap.put("beginAndEndTime", beginAndEndTime);
// 获取四大体系
String fourSystem = FourSystemEnum.getDescByCode(project.getFourSystems());
paramsMap.put("fourSystems", fourSystem);
// 获取是否数字化改革项目
String isDigitalReform = IsOrNotEnum.getDescByCode(project.getIsDigitalReform());
paramsMap.put("isDigitalReform", isDigitalReform);
// 获取是否上云
String isCloud = IsOrNotEnum.getDescByCode(project.getIsCloud());
paramsMap.put("isCloud", isCloud);
// 获取本年计划投资金额
BigDecimal yearPlanInvest = project.getAnnualPlanAmount();
paramsMap.put("yearPlanInvest",yearPlanInvest);
// TODO 根据地区编码获取当地大数据局(中心)的名称
paramsMap.put("bigDataBureauName",null);
return paramsMap;
}
}

+ 6
- 0
pmapi/src/main/java/com/ningdatech/pmapi/todocenter/model/dto/PdfGenerateDTO.java 查看文件

@@ -137,4 +137,10 @@ public class PdfGenerateDTO {

@ApiModelProperty("一地创新全省共享项目-是否开启 false:关闭 true:开启")
private Boolean isInnovateWholeProvinceShare;

@ApiModelProperty("本地区大数据局名称")
private String bidDataBureauName;

@ApiModelProperty("年度计划投资")
private BigDecimal yearPlanInvest;
}

+ 24
- 0
pmapi/src/main/java/com/ningdatech/pmapi/todocenter/model/dto/SignReqDTO.java 查看文件

@@ -0,0 +1,24 @@
package com.ningdatech.pmapi.todocenter.model.dto;

import lombok.Data;

/**
* 印章信息及位置坐标
*
* @author CMM
* @since 2023/03/16 11:56
*/
@Data
public class SignReqDTO {

private String pdfEncode64;

private Float posX;

private Float posY;

private String sealSn;

private String fileName;

}

+ 0
- 140
pmapi/src/main/java/com/ningdatech/pmapi/todocenter/utils/PdfGenerateUtil.java 查看文件

@@ -1,140 +0,0 @@
package com.ningdatech.pmapi.todocenter.utils;

import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.*;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.util.*;

/**
* pdf 生成工具
*
* @author CMM
* @since 2023/03/13 13:41
*/
@Slf4j
public class PdfGenerateUtil {

private PdfGenerateUtil() {
}


/**
* 生成填充了模板参数的pdf
*
* @param templatePdfInputStream 模板pdf流
* @param paramsMap 填充参数
* @return
*/
public static byte[] generatePdf(InputStream templatePdfInputStream,Map<String, Object> paramsMap) throws IOException {
byte[] templatePdfByteArray = readBytes(templatePdfInputStream);
return generatePdf(templatePdfByteArray, paramsMap);
}

/**
* 生成填充了模板参数的pdf
*
* @param templatePdfByteArray 模板pdf字节数组
* @param paramsMap 填充参数
* @return
*/
public static byte[] generatePdf(byte[] templatePdfByteArray, Map<String, Object> paramsMap) {

PdfReader reader = null;
ByteArrayOutputStream bos = null;
try {
//创建书写器,用于往document中书写信息
// 通过本地文件路径获取资源
reader = new PdfReader(templatePdfByteArray);
bos = new ByteArrayOutputStream();
PdfStamper stamper = new PdfStamper(reader, bos);

//使用中文字体
BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
ArrayList<BaseFont> fontList = new ArrayList<>();
fontList.add(baseFont);


AcroFields form = stamper.getAcroFields();
form.setSubstitutionFonts(fontList);

for (String fieldName : paramsMap.keySet()) {
if (paramsMap.get(fieldName) == null) {
continue;
}

if (fieldName.indexOf("Image") > 0) {
String imgPath = paramsMap.get(fieldName).toString();
int pageNo = form.getFieldPositions(fieldName).get(0).page;
Rectangle rectangle = form.getFieldPositions(fieldName).get(0).position;
float x = rectangle.getLeft();
float y = rectangle.getTop();
//根据路径读取图片
Image image = Image.getInstance(imgPath);
//获取图片页面
PdfContentByte under = stamper.getOverContent(pageNo);
//图片大小自适应
image.scaleToFit(rectangle.getWidth(), rectangle.getHeight());
//添加图片
image.setAbsolutePosition(x, y - rectangle.getHeight());
under.addImage(image);
} else {
// 设置占位字段
form.setField(fieldName, paramsMap.get(fieldName).toString());
}
}

stamper.setFormFlattening(false);
stamper.close();

} catch (Exception e) {
log.error("通过模板生成PDF失败", e.getMessage());
return null;
} finally {
try {
if (null != reader) {
reader.close();
}
if (null != bos) {
bos.close();
}

} catch (IOException e) {
log.error("close resource error", e.getMessage());
}
}

return bos.toByteArray();
}

/**
* 读取输入流到字节数组
*
* @param in
* @return
* @throws IOException
*/
private static byte[] readBytes(InputStream in) throws IOException {
//读取字节的缓冲
byte[] buffer = new byte[1024];
//最终的数据
byte[] result = new byte[0];
int size = 0;
while ((size = in.read(buffer)) != -1) {
int oldLen = result.length;
byte[] tmp = new byte[oldLen + size];
if (oldLen > 0) {//copy 旧字节
System.arraycopy(result, 0, tmp, 0, oldLen);
}
//copy 新字节
System.arraycopy(buffer, 0, tmp, oldLen, size);

result = tmp;
}
return result;
}
}



+ 10
- 14
pmapi/src/main/java/com/ningdatech/pmapi/todocenter/utils/PdfUtils.java 查看文件

@@ -1,9 +1,13 @@
package com.ningdatech.pmapi.todocenter.utils;


import cn.hutool.core.util.StrUtil;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.*;
import com.ningdatech.basic.exception.BizException;
import com.ningdatech.pmapi.common.util.StrUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
@@ -40,7 +44,7 @@ public class PdfUtils {
File directory = new File("");
//pdf输出路径
String absolutePath = directory.getAbsolutePath();
String linkPath = "\\src\\main\\resources";
String linkPath = "\\pmapi\\src\\main\\resources";
String filePath = absolutePath + linkPath + "\\template\\fileout";
if(!new File(filePath).exists()){
new File(filePath).mkdir();
@@ -58,13 +62,14 @@ public class PdfUtils {
//替换参数、多个参数多次替换
for (String fieldName : paramsMap.keySet()) {
if (paramsMap.get(fieldName) == null) {
continue;
// 没有值的字段使用-覆盖
htmlInfo = htmlInfo.replace("#" + fieldName + "#", "");
}else {
// 设置占位字段
htmlInfo = htmlInfo.replace("#" + fieldName + "#", paramsMap.get(fieldName).toString());
}
// 设置占位字段
htmlInfo = htmlInfo.replace("#" + fieldName + "#", paramsMap.get(fieldName).toString());
}


//生成临时文件
String htmlFileName = UUID.randomUUID().toString().replace("-","") + ".html";
String htmlFilePath = filePath + File.separator + htmlFileName;
@@ -95,15 +100,6 @@ public class PdfUtils {

inputStream = new FileInputStream(pdfFilePath);

//删除临时文件
File delFile = new File(pdfFilePath);
if(delFile.exists()){
delFile.delete();
}
File delHtmlFile = new File(htmlFilePath);
if(delHtmlFile.exists()){
delHtmlFile.delete();
}
// 返回生成的pdf文件字节数组
return readBytes(inputStream);
} catch (IOException e) {


二进制
pmapi/src/main/resources/template/fileout/c34f631755a04532a0116494fd5f99ac.pdf 查看文件


+ 0
- 254
pmapi/src/main/resources/template/盖章文件.html 查看文件

@@ -1,254 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
html,
body {
padding: 0;
margin: 0;
}
.pdf {
margin: 0 auto;
padding: 10px 0 30px;
text-align: center;
}
.title {
padding: 0 0 40px 0;
font-size: 34px;
margin: 40px 0 0 0;
}
.tab {
padding: 0 20px;
}
.projectId {
color: #999999;
text-align: left;
margin-bottom: 8px;
}
.projectId > .time {
float: right;
}

table {
width: 100%;
border-collapse: collapse;
font-size: 16px;
table-layout: fixed;
word-break: break-all;
text-align: left;
}
td {
padding: 15px 8px;
border: 1px solid;
}
.tabTit {
background-color: #eee;
}
.label {
width: 150px;
}
.sealTd {
height: 200px;
position: relative;
}
.seal {
position: absolute;
right: 20px;
bottom: 30px;
width: 150px;
}
.seal > .time {
text-align: right;
}
.content {
height: 150px;
}
.text {
min-height: 150px;
}
</style>
</head>
<body>
<div class="pdf">
<p class="title">
<span></span>
】预审申请单
</p>
<div class="tab">
<p class="projectId">
<span>
项目编号:
<span></span>
</span>
<span class="time"></span>
</p>
<table>
<tbody>
<tr>
<td class="tabTit" colspan="4">项目基本信息</td>
</tr>
<tr>
<td class="label">项目名称</td>
<td colspan="3"></td>
</tr>
<tr>
<td class="label">是否临时增补</td>
<td></td>
<td class="label">是否一地创新全省共享项目</td>
<td></td>
</tr>
<tr>
<td class="label">项目负责人</td>
<td></td>
<td class="label">负责人手机号</td>
<td></td>
</tr>
<tr>
<td class="label">项目联系人</td>
<td></td>
<td class="label">项目联系人手机号</td>
<td></td>
</tr>
<tr>
<td class="label">建设单位</td>
<td></td>
<td class="label">建设单位统一社会信用代码</td>
<td></td>
</tr>
<tr>
<td class="label">项目类型</td>
<td></td>
<td class="label">是否首次新建</td>
<td></td>
</tr>
<tr>
<td class="label">预算年度</td>
<td></td>
<td class="label">建设起止时间</td>
<td></td>
</tr>
<tr>
<td class="label">四大体系</td>
<td colspan="3"></td>
</tr>
<tr>
<td class="label">是否数字化改革项目</td>
<td></td>
<td class="label">综合业务领域</td>
<td></td>
</tr>
<tr>
<td class="label">立项依据</td>
<td colspan="3"></td>
</tr>
<tr>
<td class="label">是否上云</td>
<td></td>
<td class="label">云类型</td>
<td></td>
</tr>
<tr>
<td class="label">项目简介</td>
<td colspan="3"></td>
</tr>
<tr>
<td class="tabTit" colspan="4">资金申报情况</td>
</tr>
<tr>
<td class="label">申报金额</td>
<td colspan="3"></td>
</tr>
<tr>
<td class="label">自有资金</td>
<td></td>
<td class="label">政府投资-本级财政资金</td>
<td></td>
</tr>
<tr>
<td class="label">政府投资-上级补助资金</td>
<td></td>
<td class="label">银行贷款</td>
<td></td>
</tr>
<tr>
<td class="label">自有资金</td>
<td></td>
<td class="label">政府投资-本级财政资金</td>
<td></td>
</tr>
<tr>
<td class="label">其他资金</td>
<td colspan="3"></td>
</tr>
<tr>
<td class="label">2021年计划投资(万元)</td>
<td colspan="3"></td>
</tr>
<tr>
<td class="tabTit" colspan="4">资金分配情况</td>
</tr>
<tr>
<td class="label">软件开发</td>
<td></td>
<td class="label">云资源、硬件购置</td>
<td></td>
</tr>
<tr>
<td class="label">第三方服务</td>
<td colspan="3"></td>
</tr>
<tr>
<td class="tabTit" colspan="4">年度支付计划</td>
</tr>
<tr>
<td class="label">年度支付金额</td>
<td colspan="3"></td>
</tr>
<tr>
<td class="label">自有资金</td>
<td></td>
<td class="label">政府投资-本级财政资金</td>
<td></td>
</tr>
<tr>
<td class="label">政府投资-上级补助资金</td>
<td></td>
<td class="label">银行贷款</td>
<td></td>
</tr>
<tr>
<td class="label">其他资金</td>
<td colspan="3"></td>
</tr>
<tr>
<td class="tabTit" colspan="4">备注</td>
</tr>
<tr>
<td class="label">备注</td>
<td colspan="3"></td>
</tr>
<tr>
<td class="tabTit" colspan="4">单位意见</td>
</tr>
<tr>
<td class="label">本级主管单位意见(盖章)</td>
<td colspan="3" class="text content"></td>
</tr>
<tr>
<td class="label">上级主管单位意见(盖章)</td>
<td colspan="3" class="text content"></td>
</tr>
<tr>
<td class="label">{本地区大数据局的名称}意见(盖章)</td>
<td colspan="3" class="text content"></td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
</html>

+ 47
- 10
pmapi/src/main/resources/template/预审申请单.html 查看文件

@@ -1,5 +1,8 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:font-family="http://www.w3.org/1999/xhtml">
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:font-family="http://www.w3.org/1999/xhtml"
>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
@@ -9,7 +12,7 @@
body {
padding: 0;
margin: 0;
font-family:SimSun;
font-family: SimSun;
}
.pdf {
margin: 0 auto;
@@ -20,7 +23,7 @@
padding: 0 0 40px 0;
font-size: 34px;
margin: 40px 0 0 0;
font-family:SimSun;
font-family: SimSun;
}
.tab {
padding: 0 20px;
@@ -72,12 +75,16 @@
.text {
min-height: 150px;
}
.content > .right {
float: right;
margin-right: 10px;
}
</style>
</head>
<body>
<div class="pdf">
<p class="title">
预审申请单
<span>#title#</span>
</p>
<div class="tab">
<p class="projectId">
@@ -231,15 +238,45 @@
</tr>
<tr>
<td class="label">本级主管单位意见(盖章)</td>
<td colspan="3" class="text content"></td>
<td colspan="3" class="text content">
<div class="right">
<p>
<span>#superOrgOpinion#</span>
</p>
<p>
<span>#superOrgAuditDate#</span>
</p>
</div>
</td>
</tr>
<tr>
<td class="label">上级主管单位意见(盖章)</td>
<td colspan="3" class="text content"></td>
</tr>
<tr>
<td class="label">{本地区大数据局的名称}意见(盖章)</td>
<td colspan="3" class="text content"></td>
<td colspan="3" class="text content">
<div class="right">
<p>
<span>#higherOrgOpinion#</span>
</p>
<p>
<span>#higherOrgAuditDate#</span>
</p>
</div>
</td>
</tr>
<tr>
<td class="label">
<span>#bigDataBureauName#</span>
意见(盖章)
</td>
<td colspan="3" class="text content">
<div class="right">
<p>
<span>#bigDataBureauOpinion#</span>
</p>
<p>
<span>#bigDataBureauAuditDate#</span>
</p>
</div>
</td>
</tr>
</tbody>
</table>


二进制
pmapi/src/main/resources/template/预审申请单.pdf 查看文件


+ 6
- 9
pmapi/src/test/java/com/ningdatech/pmapi/todocenter/TodoCenterTest.java 查看文件

@@ -17,7 +17,6 @@ import com.ningdatech.pmapi.staging.service.INdWorkNoticeStagingService;
import com.ningdatech.pmapi.todocenter.bean.entity.WorkNoticeInfo;
import com.ningdatech.pmapi.todocenter.manage.TodoCenterManage;
import com.ningdatech.pmapi.todocenter.model.dto.PdfGenerateDTO;
import com.ningdatech.pmapi.todocenter.utils.PdfGenerateUtil;
import com.ningdatech.pmapi.todocenter.utils.PdfUtils;
import com.ningdatech.pmapi.user.entity.UserInfo;
import com.ningdatech.pmapi.user.service.IUserInfoService;
@@ -28,13 +27,10 @@ import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.concurrent.*;

import static com.ningdatech.pmapi.todocenter.constant.WorkNotice.PASS_MSG_TEMPLATE;

/**
@@ -127,7 +123,7 @@ public class TodoCenterTest extends AppTests {
public void GeneratePdf(){
// 获取本地目录的pdf模板
String fileName = "预审申请单";
InputStream pdfInputStream =
InputStream htmlInputStream =
this.getClass().getClassLoader().getResourceAsStream("template/" + fileName + ".html");
// 获取表单数据
ProjectDetailVO projectDetail = projectLibManage.getProjectDetail(44L);
@@ -153,10 +149,11 @@ public class TodoCenterTest extends AppTests {
paramsMap.put("isDigitalReform", "否");
Integer isCloud = projectDetail.getIsCloud();
paramsMap.put("isCloud", "否");
paramsMap.put("yearPlanInvest",null);
paramsMap.put("bigDataBureauName",null);

// 生成pdf字节数组

byte[] pdf = pdfUtils.generatePdf(pdfInputStream, paramsMap);
byte[] pdf = pdfUtils.generatePdf(htmlInputStream, paramsMap);

// 转换成MultipartFile
MultipartFile multipartFile = new MockMultipartFile("file", fileName + ".pdf", "application/pdf", pdf);
@@ -169,8 +166,8 @@ public class TodoCenterTest extends AppTests {
project.setPretrialFileId(resultVO.getId());

try {
if (null != pdfInputStream) {
pdfInputStream.close();
if (null != htmlInputStream) {
htmlInputStream.close();
}
} catch (IOException e) {
e.printStackTrace();


+ 6
- 0
pom.xml 查看文件

@@ -169,6 +169,12 @@
<artifactId>flying-saucer-pdf-itext5</artifactId>
<version>9.0.3</version>
</dependency>
<!--将html转换成pdf-->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>html2pdf</artifactId>
<version>2.0.2</version>
</dependency>

</dependencies>
</dependencyManagement>


正在加载...
取消
保存