| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366 |
- package com.kingdee.eas.custom.esign.util;
- import com.alibaba.fastjson.JSON;
- import com.alibaba.fastjson.JSONArray;
- import com.alibaba.fastjson.JSONObject;
- import com.kingdee.eas.base.permission.UserInfo;
- import org.apache.commons.lang3.StringUtils;
- import com.kingdee.bos.BOSException;
- import com.kingdee.bos.Context;
- import com.kingdee.bos.dao.ormapping.ObjectUuidPK;
- import com.kingdee.bos.metadata.entity.EntityViewInfo;
- import com.kingdee.bos.metadata.entity.FilterInfo;
- import com.kingdee.bos.metadata.entity.FilterItemInfo;
- import com.kingdee.bos.metadata.entity.SelectorItemCollection;
- import com.kingdee.bos.metadata.query.util.CompareType;
- import com.kingdee.eas.base.attachment.*;
- import com.kingdee.eas.basedata.person.PersonInfo;
- import com.kingdee.eas.common.EASBizException;
- import com.kingdee.eas.custom.esign.*;
- import com.kingdee.eas.custom.esign.tsign.hz.comm.EsignHttpResponse;
- import com.kingdee.shr.attachment.*;
- import com.kingdee.shr.attachment.AttachmentTypeEnum;
- import com.kingdee.shr.base.syssetting.exception.ShrWebBizException;
- import com.kingdee.shr.base.syssetting.ml.SHRWebResource;
- import com.kingdee.shr.ml.util.MutilanUtils;
- import com.kingdee.util.LocaleUtils;
- import com.kingdee.util.STConverter;
- import org.apache.log4j.Logger;
- import java.io.IOException;
- import java.text.MessageFormat;
- import java.util.HashSet;
- import java.util.Locale;
- import java.util.Set;
- /**
- * @Description 签署文件同步
- * @Date 2025/11/29 14:22
- * @Created by heyuan
- */
- public class SyncSignedFilesUtil {
- private static Logger logger = Logger.getLogger(SyncSignedFilesUtil.class);
- // 员工页签的uipk
- private static final String EMPPAGEUIPK = "com.kingdee.eas.custom.esign.app.FileTab.form";
- private static final SelectorItemCollection updateSic = new SelectorItemCollection();
- static {
- updateSic.add("Fivouchered");
- }
- /**
- * 同步员工页面的电子签附件信息。
- * <p>
- * 根据传入的签署ID(signId),从电子签全域状态总览表中获取对应的记录,
- * 并判断是否已同步过附件。如果尚未同步,则通过e签宝接口下载相关文件和附件,
- * 并保存到系统中。
- * </p>
- *
- * @param ctx 上下文对象,用于获取业务服务实例
- * @param signId 签署记录的唯一标识(即电子签全域状态总览表的主键)
- * @throws BOSException 当出现业务异常时抛出,例如:已同步、流程ID为空、员工信息缺失或HTTP请求失败等
- */
- public static void syncAttachmentsForEmpPage(Context ctx, String signId) throws BOSException {
- try {
- IESignGlobalStatusOverview iESignGlobalStatusOverview =
- ESignGlobalStatusOverviewFactory.getLocalInstance(ctx);
- SelectorItemCollection sic = new SelectorItemCollection();
- sic.add("*");
- // 获取电子签全域状态总览表信息
- ESignGlobalStatusOverviewInfo info = iESignGlobalStatusOverview.getESignGlobalStatusOverviewInfo(new ObjectUuidPK(signId), sic);
- // 判断是否已经同步过附件
- boolean fivouchered = info.isFivouchered();
- if (fivouchered) {
- throw new BOSException(MessageFormat.format("电子签全域状态总览表 [{0}],签署文件已经同步,请勿重复同步", info.getNumber()));
- }
- // 检查e签宝流程ID是否存在
- String signFlowId = info.getSignFlowId();
- if (StringUtils.isBlank(signFlowId)) {
- throw new BOSException(MessageFormat.format("电子签全域状态总览表 [{0}],e签宝流程id为空!", info.getNumber()));
- }
- // 检查关联的员工信息是否存在
- PersonInfo person = info.getPerson();
- if (person == null) {
- throw new BOSException(MessageFormat.format("电子签全域状态总览表 [{0}],员工为空!", info.getNumber()));
- }
- IFileTab iFileTab = FileTabFactory.getLocalInstance(ctx);
- FileTabCollection fileTabCollection = iFileTab.getFileTabCollection("where person.id ='" + person.getId() + "'");
- FileTabInfo fileTabInfo = null;
- if (fileTabCollection.isEmpty()) {
- fileTabInfo = new FileTabInfo();
- fileTabInfo.setPerson(person);
- iFileTab.addnew(fileTabInfo);
- } else {
- fileTabInfo = fileTabCollection.get(0);
- }
- // 调用e签宝接口获取文件下载地址
- EsignHttpResponse response = EsignHttpUtil.getFile_download_url(ctx, signFlowId, 3600, info.getEfileId());
- JSONObject jsonObject = JSON.parseObject(response.getBody());
- Integer code = (Integer) jsonObject.get("code");
- // 处理返回结果并保存文件和附件
- if (code == 0) {
- JSONObject jsonData = jsonObject.getJSONObject("data");
- saveAttachment(ctx, fileTabInfo, jsonData.getJSONArray("files"));
- saveAttachment(ctx, fileTabInfo, jsonData.getJSONArray("attachments"));
- }
- //更新电子签全域状态总览表信息
- info.setFivouchered(true);
- iESignGlobalStatusOverview.updatePartial(info, updateSic);
- } catch (Exception e) {
- e.printStackTrace();
- throw new BOSException(e);
- }
- }
- /**
- * 保存附件
- *
- * @param ctx
- * @param fileTabInfo
- * @throws IOException
- * @throws ShrWebBizException
- * @throws BOSException
- * @throws EASBizException
- */
- private static void saveAttachment(
- Context ctx,
- FileTabInfo fileTabInfo,
- JSONArray attachments
- ) throws IOException, BOSException, EASBizException {
- IESignTemplateFileEntry ieSignTemplateFileEntry = ESignTemplateFileEntryFactory.getLocalInstance(ctx);
- IAttachment iAttachment = AttachmentFactory.getLocalInstance(ctx);
- IBoAttchAsso iBoAttchAsso = BoAttchAssoFactory.getLocalInstance(ctx);
- ISHRAttachmentExt ishrAttachmentExt = SHRAttachmentExtFactory.getLocalInstance(ctx);
- UserInfo userInfo = (UserInfo) ctx.get("UserInfo");
- String userId = userInfo.getId().toString();
- // 遍历并保存签署生成的正式文件
- for (int i = 0; i < attachments.size(); i++) {
- JSONObject fileMap = attachments.getJSONObject(i);
- String fileName = fileMap.getString("fileName");
- String downloadUrl = fileMap.getString("downloadUrl");
- String fileId = "fileTab" + fileMap.getString("fileId");
- logger.error("fileId: " + fileId);
- if (StringUtils.isBlank(downloadUrl)) {
- logger.error("下载地址为空!");
- continue;
- }
- // 查询对应模板文件的组件ID
- String componentId = ieSignTemplateFileEntry.findByFileName(fileName);
- // 查询附件是否存在,如果存在需要删除
- delAttachment(ctx, fileId);
- byte[] content = DownloaderUtil.downloadFileToByteArray(downloadUrl);
- // 检查文件名是否包含脚本攻击
- fileName = checkScriptAttack(fileName);
- if( fileName.lastIndexOf(46)<=0) {
- fileName +=".pdf";
- }
- String mainname = fileName.substring(0, fileName.lastIndexOf(46));
- String extname = fileName.substring(fileName.lastIndexOf(46) + 1, fileName.length());
- extname = extname.toLowerCase();
- //附件对象
- AttachmentInfo ai = new AttachmentInfo();
- setAttMulNameAndDesc(ctx, ai, mainname, null);
- ai.setSimpleName(extname);
- ai.setFile(content);
- ai.setIsShared(false);
- //ai.setNumber();
- ai.setSharedDesc(SHRWebResource.getString("com.kingdee.shr.base.syssetting.SHRSyssettingResource", "false"));
- int size = content.length;
- if (size < 1024) {
- ai.setSize(size + SHRWebResource.getString("com.kingdee.shr.base.syssetting.SHRSyssettingResource", "byte"));
- } else {
- ai.setSize(size / 1024 + "KB");
- }
- ai.setSizeInByte(size);
- ai.setAttachID(fileId);//附件id
- ai.setType(getFileType(fileName));
- ai.setBeizhu(EMPPAGEUIPK);//uipk
- //附件扩展
- SHRAttachmentExtInfo attchExt = new SHRAttachmentExtInfo();
- attchExt.setAttachment(ai);
- setAttExtMulNameAndDesc(ctx, attchExt, fileName, "");
- attchExt.setPropertyName(componentId);
- attchExt.setType(AttachmentTypeEnum.FORM);
- attchExt.setState(AttachmentState.SAVE);
- String bunding = MessageFormat.format("{0}#{1}", userId, EMPPAGEUIPK);
- attchExt.setBunding(bunding);
- attchExt.setBoID(fileTabInfo.getId().toString());//业务对象id
- try {
- //保存附件对象
- iAttachment.addnew(ai);
- } catch (Exception e) {
- e.printStackTrace();
- throw e;
- }
- attchExt.setState(AttachmentState.SAVE);
- //保存附件扩展
- BoAttchAssoInfo boAttchAssoInfo = new BoAttchAssoInfo();
- boAttchAssoInfo.setBoID(fileTabInfo.getId().toString());//业务对象id
- boAttchAssoInfo.setAssoBusObjType(String.valueOf(fileTabInfo.getBOSType()));
- // boAttchAssoInfo.setAssoType("Added Accessories", LocaleUtils.locale_l1);
- // boAttchAssoInfo.setAssoType("Added Accessories", LocaleUtils.locale_l2);
- // boAttchAssoInfo.setAssoType("Added Accessories", LocaleUtils.locale_l3);
- boAttchAssoInfo.setAttachment(ai);
- //保存
- iBoAttchAsso.addnew(boAttchAssoInfo);
- ishrAttachmentExt.addnew(attchExt);
- }
- }
- /**
- * 删除附件及相关关联信息
- *
- * @param ctx 上下文对象,用于获取服务实例
- * @param fileId 文件ID,标识要删除的附件
- * @throws BOSException 业务对象服务异常
- * @throws EASBizException EAS业务异常
- */
- private static void delAttachment(Context ctx, String fileId) throws BOSException, EASBizException {
- if (StringUtils.isNotBlank(fileId)) {
- IAttachment iAttachment = AttachmentFactory.getLocalInstance(ctx);
- IBoAttchAsso iBoAttchAsso = BoAttchAssoFactory.getLocalInstance(ctx);
- ISHRAttachmentExt ishrAttachmentExt = SHRAttachmentExtFactory.getLocalInstance(ctx);
- FilterInfo filterInfo = new FilterInfo();
- filterInfo.getFilterItems().add(new FilterItemInfo("attachID", fileId));
- EntityViewInfo viewInfo = EntityViewInfo.getInstance(filterInfo, null, null);
- //判断是否存在附件
- if (iAttachment.exists(filterInfo)) {
- // 获取附件集合
- AttachmentCollection attachmentCol = iAttachment.getAttachmentCollection(viewInfo);
- ObjectUuidPK[] attachMentIds = new ObjectUuidPK[attachmentCol.size()];
- Set<String> delIds = new HashSet<String>();
- // 收集需要删除的附件ID
- for (int i = 0; i < attachmentCol.size(); i++) {
- String id = attachmentCol.get(i).getId().toString();
- attachMentIds[i] = new ObjectUuidPK(id);
- delIds.add(id);
- }
- // 构造删除条件并执行删除操作
- FilterInfo deleteFilterInfo = new FilterInfo();
- deleteFilterInfo.getFilterItems().add(new FilterItemInfo("attachment.id", delIds, CompareType.INCLUDE));
- iAttachment.delete(attachMentIds);
- iBoAttchAsso.delete(deleteFilterInfo);
- ishrAttachmentExt.delete(deleteFilterInfo);
- }
- }
- }
- /**
- * 设置附件扩展信息的多语言名称和描述
- *
- * @param ctx 上下文对象,用于获取当前区域设置
- * @param info 附件扩展信息对象,要设置名称和描述的目标对象
- * @param name 附件名称
- * @param desc 附件描述
- */
- private static void setAttExtMulNameAndDesc(Context ctx, SHRAttachmentExtInfo info, String name, String desc) {
- if (info != null && !org.apache.commons.lang3.StringUtils.isEmpty(name)) {
- Locale locale = ctx.getLocale();
- info.setName(name, LocaleUtils.locale_l1);
- info.setDescription(desc, LocaleUtils.locale_l1);
- // 根据当前区域设置确定简体/繁体中文的处理方式
- if (LocaleUtils.locale_l1.getDisplayName().equals(LocaleUtils.getLocaleString(locale))) {
- // 当前区域为locale_l1时,将名称和描述同时设置到locale_l2和locale_l3
- info.setName(name, LocaleUtils.locale_l2);
- info.setName(name, LocaleUtils.locale_l3);
- info.setDescription(desc, LocaleUtils.locale_l2);
- info.setDescription(desc, LocaleUtils.locale_l3);
- } else if (LocaleUtils.locale_l2.getDisplayName().equals(LocaleUtils.getLocaleString(locale))) {
- // 当前区域为locale_l2时,进行简繁转换处理
- info.setName(name, LocaleUtils.locale_l2);
- info.setName(STConverter.sc2tc(name), LocaleUtils.locale_l3);
- if (!org.apache.commons.lang3.StringUtils.isEmpty(desc)) {
- info.setDescription(desc, LocaleUtils.locale_l2);
- info.setDescription(STConverter.sc2tc(desc), LocaleUtils.locale_l3);
- }
- } else {
- // 其他情况,进行反向简繁转换处理
- info.setName(STConverter.tc2sc(name), LocaleUtils.locale_l2);
- info.setName(name, LocaleUtils.locale_l3);
- if (!org.apache.commons.lang3.StringUtils.isEmpty(desc)) {
- info.setDescription(STConverter.tc2sc(desc), LocaleUtils.locale_l2);
- info.setDescription(desc, LocaleUtils.locale_l3);
- }
- }
- }
- }
- /**
- * 根据文件全名获取文件类型描述
- *
- * @param fullname 文件全名(包含扩展名)
- * @return 文件类型的描述字符串,如果扩展名未知则返回未知类型描述
- */
- private static String getFileType(String fullname) {
- // 提取文件扩展名
- String extname = fullname.substring(fullname.lastIndexOf(46) + 1, fullname.length());
- // 判断是否为Word文档类型
- if (!"doc".equalsIgnoreCase(extname) && !"docx".equalsIgnoreCase(extname)) {
- // 判断是否为Excel文档类型
- if (!"xls".equalsIgnoreCase(extname) && !"xlsx".equalsIgnoreCase(extname) && !"xlsm".equalsIgnoreCase(extname) && !"xlsb".equalsIgnoreCase(extname)) {
- // 判断是否为PowerPoint文档类型
- if (!"ppt".equalsIgnoreCase(extname) && !"pptx".equalsIgnoreCase(extname) && !"pptm".equalsIgnoreCase(extname)) {
- // 判断是否为文本文件或其他未知类型
- return "txt".equalsIgnoreCase(extname) ? SHRWebResource.getString("com.kingdee.shr.base.syssetting.SHRSyssettingResource", "text") : MessageFormat.format(SHRWebResource.getString("com.kingdee.shr.base.syssetting.SHRSyssettingResource", "unknow_type"), extname);
- } else {
- return SHRWebResource.getString("com.kingdee.shr.base.syssetting.SHRSyssettingResource", "microsoft_ppt");
- }
- } else {
- return SHRWebResource.getString("com.kingdee.shr.base.syssetting.SHRSyssettingResource", "microsoft_excel");
- }
- } else {
- return SHRWebResource.getString("com.kingdee.shr.base.syssetting.SHRSyssettingResource", "microsoft_word");
- }
- }
- /**
- * 检查并防止脚本攻击,对输入字符串中的HTML标签符号进行转义处理
- *
- * @param str 待检查和处理的字符串
- * @return 处理后的字符串,将HTML标签符号"<"和">"分别替换为"<"和">"
- */
- private static String checkScriptAttack(String str) {
- // 检查字符串是否非空
- if (!org.apache.commons.lang3.StringUtils.isEmpty(str)) {
- // 如果包含"<"符号,则进行HTML转义替换
- if (str.contains("<")) {
- str.replaceAll("<", "<");
- }
- // 如果包含">"符号,则进行HTML转义替换
- if (str.contains(">")) {
- str.replaceAll(">", ">");
- }
- }
- return str;
- }
- /**
- * 设置附件的多语言名称和描述信息
- *
- * @param ctx 上下文对象,用于获取多语言环境信息
- * @param att 附件信息对象,需要设置名称和描述的目标对象
- * @param name 附件名称,如果为空则不进行设置
- * @param desc 附件描述信息
- */
- private static void setAttMulNameAndDesc(Context ctx, AttachmentInfo att, String name, String desc) {
- // 当附件对象不为空且名称不为空时,设置附件的多语言名称和描述
- if (att != null && !org.apache.commons.lang3.StringUtils.isEmpty(name)) {
- MutilanUtils.setMultiFieldValueToBean(ctx, "name", att, name);
- //MutilanUtils.setMultiFieldValueToBean(ctx, "description", att, desc);
- }
- }
- }
|