初始化

This commit is contained in:
2026-02-11 11:21:50 +08:00
commit de87db8081
82 changed files with 6789 additions and 0 deletions

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<plugin>
<id>esign</id>
<name>致远E签宝集成封装</name>
<category>20260122</category>
</plugin>

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans default-autowire="byName">
<bean id="esignConfigProvider" class="com.seeyon.apps.esign.config.EsignConfigProvider" />
<bean id="sealDocSyncJob" class="com.seeyon.apps.esign.job.SealDocSyncJob" />
<bean id="contractCompareFieldCtrl" class="com.seeyon.apps.esign.fieldCtrl.ContractCompareFieldCtrl" />
<bean id="esignMultipleSignerNode" class="com.seeyon.apps.esign.node.EsignMultipleSignerNode" />
<bean id="esignOneSignerNode" class="com.seeyon.apps.esign.node.EsignOneSignerNode" />
<bean id="esignUploadFileService" class="com.seeyon.apps.esign.service.EsignUploadFileService" />
<bean id="defaultSignerBuilder" class="com.seeyon.apps.esign.po.signer.DefaultSignerBuilder" />
<bean id="esignByTemplateService" class="com.seeyon.apps.esign.service.EsignByTemplateService" />
<bean id="flowFormSignParamBuildFactory" class="com.seeyon.apps.esign.service.FlowFormSignParamBuildFactory" />
<bean id="normalFormSignParamBuildFactory" class="com.seeyon.apps.esign.service.NormalFormSignParamBuildFactory" />
<bean id="sealService" class="com.seeyon.apps.esign.service.SealService" />
<bean id="signLinkService" class="com.seeyon.apps.esign.service.SignLinkService" />
<bean id="tokenCacheManager" class="com.seeyon.apps.esign.service.TokenCacheManager" />
<bean id="esignFlowQueryService" class="com.seeyon.apps.esign.service.EsignFlowQueryService" />
<bean id="protUtil" class="com.seeyon.apps.esign.utils.ProtUtil" />
<!-- 定义接口实现类 -->
<bean id="esignCallbackFlowBizService" class="com.seeyon.apps.esign.service.EsignCallbackFlowBizService"/>
<!-- 注入数组类型的Bean -->
<bean id="esignPluginApi" class="com.seeyon.apps.esign.EsignPluginApi"/>
<bean name="contractCreateService" class="com.seeyon.apps.esign.service.ContractCreateService">
<property name="signParamBuildFactories">
<list>
<ref bean="flowFormSignParamBuildFactory"/>
<ref bean="normalFormSignParamBuildFactory"/>
</list>
</property>
</bean>
</beans>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans default-autowire="byName">
<bean name="/esigncallback.do" class="com.seeyon.apps.esign.controller.DefaultEsignCallBackController">
</bean>
</beans>

View File

@@ -0,0 +1,36 @@
.customButton_class_box {
width: 35%;
line-height: 24px;
height:24px;
color: #1f85ec;
cursor: pointer;
font-family: "Microsoft YaHei"!important;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
word-break:keep-all;
box-sizing: border-box;
-webkit-box-sizing : border-box;
-moz-box-sizing : border-box;
text-align: center;
outline: none;
border: 1px solid #1f85ec;
background-color: #fff;
border-radius: 15px;
-webkit-border-radius: 15px;
-moz-border-radius: 15px;
}
.customInputArea{
width: 65%;
height:auto;
color: #1f85ec;
font-family: "Microsoft YaHei"!important;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
word-break:keep-all;
}
.customButton_box_content{
width: 100%;
height: auto;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

View File

@@ -0,0 +1,104 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>e签宝合同比对</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<style>
body {
height: 100vh;
margin: 0;
font-family: Arial, sans-serif;
background: #f5f5f7;
}
#content {
padding: 20px;
overflow-y: auto;
}
.file-item {
display: flex;
align-items: center;
padding: 10px;
background: white;
border-radius: 8px;
margin-bottom: 10px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.file-item input {
margin-right: 12px;
}
.search-bar {
display: flex;
align-items: center;
gap: 20px;
margin-bottom: 20px;
}
.search-bar input {
width: 400px;
padding: 10px;
border: 1px solid #ccc;
border-radius: 5px;
}
button {
padding: 10px 20px;
background-color: #4A90E2;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}
button:hover {
background-color: #0056b3;
}
#confirm {
margin-right: 20px;
}
.pagination {
display: flex;
justify-content: center;
margin-top: 10px;
}
.pagination button {
margin: 0 5px;
padding: 4px 8px;
cursor: pointer;
}
</style>
</head>
<body>
<div id="content">
<div id="file-list"></div>
<div id="file-pagination" class="pagination"></div>
</div>
<script src="../js/compareBiz.js"></script>
<script>
function OK() {
var ids = '';
const checkList = $('#file-list input:checked');
console.log('checkList:' + checkList)
if (checkList.length === 0) {
console.log('没有选中的文件');
return ''; // 如果没有选中的复选框,直接返回空字符串
}
checkList.each(function() {
ids += $(this).val(); // 拼接 id
});
return ids;
}
</script>
</body>
</html>

View File

@@ -0,0 +1,99 @@
$(document).ready(async function() {
const apiBaseUrl = window.location.origin;
let currentFilePage = 1;
let totalFilePages = 1;
let searchKeyword;
const filePageSize = 10;
const dataList = await pageQueryTemplates();
renderTemplates(dataList);
function renderTemplates(list) {
const container = $('#file-list');
container.empty();
list.forEach(file => {
const fileItem = $(`
<div class="file-item">
<input type="radio" value=${file.signTemplateId} title=${file.signTemplateName}> ${file.signTemplateName}
</div>
`);
container.append(fileItem);
});
filePagination()
}
async function pageQueryTemplates() {
const pageIndex = currentFilePage;
const response = await fetch(
`${apiBaseUrl}/seeyon/rest/cap4/etemplate/querypage?pageNum=${pageIndex}`, {}
);
const res = await response.json();
// 校验返回值
console.log(res)
let respData = res.data;
totalFilePages = Math.ceil(respData.total / filePageSize);
return res.data.templateList;
}
async function getContractCompareUrl(templateId,templateFileId) {
const response = await fetch(
`${apiBaseUrl}/seeyon/rest/cap4/etemplate/compareurl?templateId=${templateId}&templateFileId=${templateFileId}`, {}
);
const res = await response.json();
// 校验返回值
}
function filePagination() {
// 分页逻辑
const pagination = $('#file-pagination');
pagination.empty();
const firstBtn = $('<button>首页</button>');
const prevBtn = $('<button>上一页</button>');
const nextBtn = $('<button>下一页</button>');
const pageInfo = $(`<span>第 ${currentFilePage} 页</span>`);
// 判断是否禁用按钮
prevBtn.prop('disabled', currentFilePage === 1);
// 首页按钮点击事件
firstBtn.click(async () => {
currentFilePage = 1; // 跳转到第一页
await loadTemplates(); // 加载文件
});
// 上一页按钮点击事件
prevBtn.click(async () => {
if (currentFilePage <= 1) return; // 防止重复请求
currentFilePage--; // 页码减一
await loadTemplates(); // 加载文件
});
// 下一页按钮点击事件
nextBtn.click(async () => {
currentFilePage++; // 页码加一
await loadTemplates(); // 加载文件
});
// 加载文件的逻辑
async function loadTemplates() {
let tempTemplateList;
tempTemplateList = await pageQueryTemplates();
renderTemplates(tempFileList); // 渲染文件列表
pageInfo.text(`${currentFilePage}`); // 更新页数信息
}
// 添加按钮到分页容器
pagination.append(firstBtn, prevBtn, pageInfo, nextBtn);
}
function getCookie(name) {
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) return parts.pop().split(';').shift();
}
})

View File

@@ -0,0 +1,207 @@
(function(factory) {
var nameSpace = 'field_8899554679928334458';
if (!window[nameSpace]) {
console.log("开始实例化控件")
var Builder = factory();
window[nameSpace] = {
instance: {}
};
window[nameSpace].init = function(options) {
window[nameSpace].instance[options.privateId] = new Builder(options);
};
}
})(function() {
function App(options) {
var self = this;
self.initParams(options);
//初始化dom
self.initDom();
//事件
self.events();
}
App.prototype = {
initParams: function(options) {
console.log("开始初始化参数")
var self = this;
self.adaptation = options.adaptation;
self.privateId = options.privateId;
self.preUrl = options.url_prefix;
self.adaptation.formMessage = options.formMessage;
self.messageObj = options.getData;
console.log(self.messageObj)
},
initDom: function() {
var self = this;
console.log("开始渲染dom")
dynamicLoading.css(self.preUrl + '/css/contractCompareBtn.css');
self.appendChildDom();
},
events: function() {
var self = this;
// 监听是否数据刷新
console.log("设置事件监听")
self.adaptation.ObserverEvent.listen('Event' + self.privateId, function() {
self.messageObj = self.adaptation.childrenGetData(self.privateId);
self.appendChildDom();
});
},
openCompareUrl: function(privateId, messageObj, adaptation) {
// 实际的业务代码方法
messageObj = adaptation.childrenGetData(privateId);
const targetObj = messageObj.formdata.formmains[adaptation.formMessage.tableName]
//backFill(ids, messageObj.id, messageObj.display, privateId,messageObj, adaptation);
//dialog.close()
console.log(targetObj)
if (targetObj) {
let contractRefId;
let templateRefId;
for (const key in targetObj) {
if (targetObj.hasOwnProperty(key) && !/^auxiliary/.test(key)) {
if (targetObj[key].display === "合同审批附件") {
console.log(targetObj[key])
contractRefId = targetObj[key].showValue;
console.log("合同附件refId: " + contractRefId)
}
if (targetObj[key].display === "原始合同模板文件") {
console.log(targetObj[key])
templateRefId = targetObj[key].showValue;
console.log("模板文件refId: " + templateRefId)
}
}
}
$.ajax({
type: "POST",
url: '/seeyon/rest/cap4/etemplate/compareurl?templateRefId=' +
templateRefId + '&contractRefId=' +
contractRefId,
data: {},
dataType: "json",
contentType: 'application/json;charset=UTF-8',
success: function(res) {
// 后台解析数据后 将数据填写到表单中
if (res.code == 0) {
window.open(res.data, "_blank");
} else {
// 报错
$.alert(res.message);
}
},
complete: function() {},
error: function(e) {
top.$.error(e.responseText);
}
});
}
},
appendChildDom: function() {
var self = this;
const params = new URLSearchParams(window.location.search);
console.log(params)
const openFrom = params.get('openFrom'); // 返回"2025"
const type = params.get('type');
var edit = !((openFrom != null && (openFrom == 'listPending' || openFrom == 'listDone' ||
openFrom == 'listSent')) || (type != null && type == 'browse'));
console.log(edit)
var domStructure = '<section class="customButton_box_content">' +
'<div>' +
'<button class = "customButton_class_box ' + self.privateId + '">' +
self.messageObj.display.escapeHTML() +
'</button>' +
'</div>' +
'</section>';
document.querySelector('#' + self.privateId).innerHTML = domStructure;
var compare = function() {
self.openCompareUrl(self.privateId, self.messageObj, self.adaptation)
}
var content = self.messageObj.formdata.content;
const picker = document.querySelector('.customButton_class_box' + '.' + self.privateId);
if (picker) {
document.querySelector('.customButton_class_box' + '.' + self.privateId)
.removeEventListener(
'click', compare);
document.querySelector('.customButton_class_box' + '.' + self.privateId).addEventListener(
'click', compare);
}
const goNewPages = document.querySelectorAll('.goToNewPage');
if (goNewPages.length > 0) {
goNewPages.forEach(element => {
element.addEventListener('click', function(e) {
window.open(e.currentTarget.dataset.href, '_blank'); //
});
});
}
//渲染隐藏权限
if (self.messageObj.auth === 'hide') {
document.querySelector('#' + self.privateId).innerHTML =
'<div class="cap4-text__browse" style="line-height: 1.8; color: rgb(0, 0, 0) !important;">***</div>';
}
}
};
function backFill(ids, fieldName, fieldDisplay, privateId, messageObj, adaptation) {
var param = new Object();
param.masterId = messageObj.formdata.content.contentDataId;
param.ids = ids;
param.formId = messageObj.formdata.content.contentTemplateId;
param.fieldName = fieldName;
param.fieldDisplay = fieldDisplay;
param.masterId = messageObj.formdata.content.contentDataId;
$.ajax({
type: "POST",
url: '/seeyon/rest/cap4/hywp/fileref',
data: JSON.stringify(param),
dataType: "json",
contentType: 'application/json;charset=UTF-8',
success: function(res) {
// 后台解析数据后 将数据填写到表单中
if (res.code == 0) {
var backfill = {};
backfill.tableName = adaptation.formMessage.tableName;
// 回填主表
backfill.tableCategory = 'formmain';
// 后台组装的data数据
console.log(res.data)
backfill.updateData = res.data;
adaptation.backfillFormControlData(backfill, privateId);
} else {
// 报错
$.alert(res.message);
}
},
complete: function() {},
error: function(e) {
top.$.error(e.responseText);
}
});
}
var dynamicLoading = {
css: function(path) {
if (!path || path.length === 0) {
throw new Error('argument "path" is required !');
}
var head = document.getElementsByTagName('head')[0];
var link = document.createElement('link');
link.href = path;
link.rel = 'stylesheet';
link.type = 'text/css';
head.appendChild(link);
},
js: function(path) {
if (!path || path.length === 0) {
throw new Error('argument "path" is required !');
}
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.src = path;
script.type = 'text/javascript';
head.appendChild(script);
}
}
return App;
});

View File

@@ -0,0 +1,44 @@
package com.seeyon.apps.esign;
import com.seeyon.apps.common.plugin.api.APluginInfoApi;
import com.seeyon.apps.common.plugin.vo.ConfigVo;
import com.seeyon.apps.esign.constants.EsignConfigConstants;
import org.springframework.stereotype.Component;
@Component
public class EsignPluginApi extends APluginInfoApi {
public EsignPluginApi() {
}
public String getPluginId() {
System.out.println(EsignConfigConstants.getPluginId());
return EsignConfigConstants.getPluginId();
}
public String getCreateUser() {
return "橙阳科技";
}
public String getDescription() {
return "E签宝对接封装";
}
public ConfigVo getDefaultConfig() {
ConfigVo configVo = new ConfigVo();
EsignConfigConstants[] var2 = EsignConfigConstants.values();
int var3 = var2.length;
for(int var4 = 0; var4 < var3; ++var4) {
EsignConfigConstants value = var2[var4];
if (value != EsignConfigConstants.plugin) {
configVo.getDevParams().put(value.name(), value.getDefaultValue());
configVo.getProdParams().put(value.name(), value.getDefaultValue());
configVo.getParamMap().put(value.name(), value.getDescription());
}
}
return configVo;
}
}

View File

@@ -0,0 +1,22 @@
package com.seeyon.apps.esign.config;
import com.seeyon.apps.common.config.ICstConfigApi;
import com.seeyon.apps.common.plugin.vo.ConfigVo;
import com.seeyon.apps.esign.constants.EsignConfigConstants;
import com.seeyon.ctp.common.AppContext;
import static com.seeyon.apps.esign.constants.EsignConfigConstants.getPluginId;
public class EsignConfigProvider {
protected ICstConfigApi cstConfigApi = (ICstConfigApi) AppContext.getBean("cstConfigApi");
public String getBizConfigByKey(EsignConfigConstants key) {
ConfigVo config = cstConfigApi.getConfig(getPluginId());
return config.getParamVal(key.name());
}
public static EsignConfigProvider getInstance() {
return (EsignConfigProvider) AppContext.getBean("esignConfigProvider");
}
}

View File

@@ -0,0 +1,19 @@
package com.seeyon.apps.esign.constants;
public class EsignApiUrl {
public static final String SEAL_GRANT_URL = "/v3/seals/org-seals/internal-auth";
public static final String SIGN_START_URL = "/v3/sign-flow/{signFlowId}/start";
public static final String SIGN_BY_FILE_URL = "/v3/sign-flow/create-by-file";
public static final String SIGN_FLOW_QUERY = "/v3/sign-flow/{signFlowId}/detail";
public static final String GET_UPLOAD_FILE_URL = "/v3/files/file-upload-url";
public static final String CONTRACT_DOWNLOAD_URL= "/v3/sign-flow/{signFlowId}/file-download-url";
public static final String PERSON_AUTH_URL = "/v3/psn-auth-url";
public static final String SIGN_POSITION_URL = "/v3/files/{fileId}/keyword-positions";
public static final String QUERY_TEMPLATES_URL = "/v3/sign-templates";
public static final String QUERY_TEMPLATE_DETAIL_URL = "/v3/sign-templates/detail";
public static final String QUERY_ORGINFO = "/v3/organizations/identity-info";
public static final String CONTRACT_COMPARE_GETURL = "/v3/contract-compare-url";
public static final String TOKEN_GET_URL = "/v1/oauth2/access_token";
public static final String SEAL_QUERY_URL = "/v3/seals/org-own-seal-list";
public static final String SIGN_LINK_GET_URL ="/v3/sign-flow/{signFlowId}/sign-url";
}

View File

@@ -0,0 +1,44 @@
package com.seeyon.apps.esign.constants;
public enum EsignConfigConstants {
plugin("esign",""),
APP_ID("7438886882",""),
APP_SECRET("325c8cc6c2a303d6cf1fb5657a16e591",""),
OA_HOST("http://cd-2.frp.one:58336",""),
ESIGN_HOST("",""),
SIGN_SERVICE_PROVIDER("ESIGN",""),
UNITNAME("","平台方组织名称"),
FORMEDITLOGINNAME("","表单修改登录名"),
updateAccountName("表单",""),
getTokenUrl("/seeyon/rest/token/","调用获取TOKEN地址"),
nodeTokenUrl("/seeyon/rest/flow/notification/","超级节点回调URL"),
restName("",""),
restPwd("",""),
signAutoDate("","是否自动加盖签署日期"),
eSignOrgId("61f735dd368c45a191f43a6711c3c88a","e签宝平台方组织id"),
formLoginName("2019","表单数据录入登录名"),
sealInfoFormCode("","印章档案编码"),
aSignPositionKeyword("甲方盖章/签字","甲方签署位置关键字"),
bSignPositionKeyword("乙方盖章/签字","乙方签署位置关键字"),
lpSignPositionKeyword("法定代表人","法人签署位置关键字"),
;
private String defaultValue;
private String description;
EsignConfigConstants(String defaultValue,String description) {
this.defaultValue = defaultValue;
this.description = description;
}
public String getDescription() {
return description;
}
public String getDefaultValue() {
return defaultValue;
}
public static String getPluginId() {
return plugin.defaultValue;
}
}

View File

@@ -0,0 +1,89 @@
package com.seeyon.apps.esign.controller;
import cn.hutool.log.Log;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.seeyon.apps.esign.po.esignapi.EsignCallbackParams;
import com.seeyon.apps.esign.service.EsignUploadFileService;
import com.seeyon.apps.esign.service.EsignCallbackFlowBizService;
import com.seeyon.ctp.common.AppContext;
import com.seeyon.ctp.common.controller.BaseController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
public class DefaultEsignCallBackController extends BaseController {
private static final Log log = Log.get(DefaultEsignCallBackController.class);
private EsignUploadFileService esignUploadFileService = (EsignUploadFileService) AppContext.getBean("esignByUploadFileService");
private EsignCallbackFlowBizService esignCallbackFlowBizService = (EsignCallbackFlowBizService) AppContext.getBean("esignCallbackFlowBizService");
public void callback(HttpServletRequest request, HttpServletResponse response) {
try {
log.info("签署回调触发");
// 签署回调处理,改变超级节点状态
String formId = request.getParameter("formId");
String tableName = request.getParameter("tablename");
String updatefield = request.getParameter("updatefield");
String statusfield = request.getParameter("statusfield");;
BufferedReader reader = request.getReader();
StringBuilder sb = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
sb.append(line);
}
String body = sb.toString();
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
EsignCallbackParams callbackParams = mapper.readValue(body, new TypeReference<EsignCallbackParams>() {
});
String flowId = callbackParams.getSignFlowId();
String action = callbackParams.getAction();
log.info("签署回调当前流程: " + flowId);
if(action.equals("SIGN_FLOW_COMPLETE")) {
if(callbackParams.getSignFlowStatus() == 2) {
Object[] fileInfos = esignUploadFileService.getDownloadFileInfo(flowId);
esignCallbackFlowBizService.handleSuccessSignCallbackBiz(tableName,updatefield,statusfield,formId,fileInfos);
}else if(callbackParams.getSignFlowStatus() == 5){
//合同过期
//esignCallbackBizService.handleExpiredSignCallbackBiz(tableName,statusfield,formId);
}else {
esignCallbackFlowBizService.handleFailSignCallbackBiz(tableName,statusfield,formId,callbackParams.getResultDescription());
}
//signLinkService.del(flowId);
response.setStatus(HttpServletResponse.SC_OK);
return;
}else if(action.equals("SIGN_MISSON_COMPLETE") && callbackParams.getSignResult() == 2 && callbackParams.getSignOrder() == 2){
//发送消息
// MessageVo messageVo = new MessageVo();
// messageVo.setBizId(flowId);
// messageVo.setMessageType("SIGN");
// thirdMessageService.sendMessage();
}
//下载合同
response.setContentType("application/json;charset=UTF-8");
response.setCharacterEncoding("UTF-8");
response.setStatus(HttpServletResponse.SC_OK);
try (OutputStream out = response.getOutputStream()) {
out.write("{\"code\":\"200\",\"msg\":\"success\"}".getBytes(StandardCharsets.UTF_8));
out.flush();
}
log.info("回调处理完成: " + flowId);
return;
} catch (Exception e) {
log.error("回调处理失败", e);
}
// response.setStatus(HttpServletResponse.SC_OK);
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
}

View File

@@ -0,0 +1,61 @@
package com.seeyon.apps.esign.fieldCtrl;
import com.seeyon.cap4.form.bean.ParamDefinition;
import com.seeyon.cap4.form.bean.fieldCtrl.FormFieldCustomCtrl;
import com.seeyon.cap4.form.util.Enums;
public class ContractCompareFieldCtrl extends FormFieldCustomCtrl {
@Override
public String getPCInjectionInfo() {
return "{path:'apps_res/cap/customCtrlResources/esignContractCompareBtnResources',jsUri:'/js/compareinit.js',initMethod:'init',nameSpace:'" + getNameSpace() + "'}";
}
@Override
public String getMBInjectionInfo() {
return "{path:'http://mapResource.v5.cmp/v1.0.0/',weixinpath:'invoice',jsUri:'js/location.js',initMethod:'init',nameSpace:'"+getNameSpace()+"'}";
}
@Override
public String getKey() {
return "8899554679928334458";
}
@Override
public boolean canUse(Enums.FormType formType) {
return true;
}
@Override
public String[] getDefaultVal(String s) {
return new String[0];
}
public String getNameSpace() {
return "field_" + this.getKey();
}
public String getFieldLength() {
return "20";
}
@Override
public String getText() {
return "e签宝合同比对按钮";
}
/**
* 控件初始化接口此接口在控件初始化的时候会调用主要用于定义控件所属插件id、在表单编辑器中的图标、表单编辑器中有哪些属性可以设置。
* 使用举例:在接口中定义自定义控件在在表单编辑器中有哪些控件属性需要配置
*/
@Override
public void init() {
//设置图标和插件ID
setPluginId("src_esign");
setIcon("cap-icon-custom-button");
// 自定义参数
ParamDefinition esignContractCompareBtnParam = new ParamDefinition();
esignContractCompareBtnParam.setParamType(Enums.ParamType.button);
addDefinition(esignContractCompareBtnParam);
}
}

View File

@@ -0,0 +1,71 @@
package com.seeyon.apps.esign.job;
import com.seeyon.aicloud.common.JsonUtils;
import com.seeyon.apps.esign.config.EsignConfigProvider;
import com.seeyon.apps.esign.constants.EsignApiUrl;
import com.seeyon.apps.esign.constants.EsignConfigConstants;
import com.seeyon.apps.esign.po.esignapi.EsignApiHeader;
import com.seeyon.apps.esign.po.esignapi.EsignBaseResp;
import com.seeyon.apps.esign.po.seal.SealInfoVo;
import com.seeyon.apps.esign.service.SealService;
import com.seeyon.apps.esign.service.TokenCacheManager;
import com.seeyon.apps.esign.utils.HttpClient;
import com.seeyon.apps.ext.quartz.AbstractQuartzTask;
import com.seeyon.ctp.common.AppContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.Map;
public class SealDocSyncJob extends AbstractQuartzTask {
private static final Log log = LogFactory.getLog(SealDocSyncJob.class);
private EsignConfigProvider configProvider = EsignConfigProvider.getInstance();
private TokenCacheManager tokenCacheManager = (TokenCacheManager) AppContext.getBean("tokenCacheManager");
private SealService sealService = (SealService) AppContext.getBean("sealService");
@Override
public String taskRun(String s) throws Exception {
log.info("开始执行印章同步任务");
syncSeals();
log.info("印章同步任务完成");
return "";
}
private void syncSeals() {
String orgId = configProvider.getBizConfigByKey(EsignConfigConstants.eSignOrgId);
String host = configProvider.getBizConfigByKey(EsignConfigConstants.ESIGN_HOST);
Integer pageNum = 1;
Integer pageSize = 20;
EsignApiHeader esignApiHeader = EsignApiHeader.build().appId(configProvider.getBizConfigByKey(EsignConfigConstants.APP_ID));
esignApiHeader.token(tokenCacheManager.getToken());
EsignBaseResp esignBaseResp = null;
Map<String,Object> dataMap = null;
do {
String url = host + EsignApiUrl.SEAL_QUERY_URL + "?" + "orgId=" + orgId + "&pageNum=" + (pageNum++) + "&pageSize=" + pageSize;
String respStr = HttpClient.httpGet(url, esignApiHeader.convert2Headers(),"UTF-8");
esignBaseResp = JsonUtils.parseObject(respStr, EsignBaseResp.class);
if(esignBaseResp.getCode() != 0) {
break;
}
dataMap = (Map<String,Object>)esignBaseResp.getData();
Object[] sealArray = (Object[]) dataMap.get("seals");
if(sealArray == null || sealArray.length == 0) {
break;
}
for (Object o : sealArray) {
SealInfoVo sealInfoVo = JsonUtils.parseObject(JsonUtils.toJSONString(o), SealInfoVo.class);
sealService.upsertOaSealDoc(sealInfoVo);
}
}while (true);
}
@Override
public String getName() {
return "E签宝印章信息同步任务";
}
}

View File

@@ -0,0 +1,50 @@
package com.seeyon.apps.esign.msg;
public class MessageVo {
private String messageType;
private String messageContent;
private String messageTime;
private String messageReceiver;
private String bizId;
public String getMessageType() {
return messageType;
}
public void setMessageType(String messageType) {
this.messageType = messageType;
}
public String getMessageContent() {
return messageContent;
}
public void setMessageContent(String messageContent) {
this.messageContent = messageContent;
}
public String getMessageTime() {
return messageTime;
}
public void setMessageTime(String messageTime) {
this.messageTime = messageTime;
}
public String getMessageReceiver() {
return messageReceiver;
}
public void setMessageReceiver(String messageReceiver) {
this.messageReceiver = messageReceiver;
}
public String getBizId() {
return bizId;
}
public void setBizId(String bizId) {
this.bizId = bizId;
}
}

View File

@@ -0,0 +1,8 @@
package com.seeyon.apps.esign.msg;
public interface ThirdMessageService {
void sendMessage(MessageVo messageVo);
void deletByBizId(String bizId);
}

View File

@@ -0,0 +1,332 @@
package com.seeyon.apps.esign.node;
import com.seeyon.apps.common.workflow.node.ACommonSuperNode;
import com.seeyon.apps.esign.config.EsignConfigProvider;
import com.seeyon.apps.esign.constants.EsignConfigConstants;
import com.seeyon.apps.esign.po.param.FlowParamSource;
import com.seeyon.apps.esign.po.signfield.NormalSignFieldConfig;
import com.seeyon.apps.esign.po.signfield.SignField;
import com.seeyon.apps.esign.po.signfield.SignFieldPosition;
import com.seeyon.apps.esign.po.signer.Signer;
import com.seeyon.apps.esign.service.ContractCreateService;
import com.seeyon.apps.esign.service.EsignByTemplateService;
import com.seeyon.apps.esign.service.EsignUploadFileService;
import com.seeyon.apps.esign.service.FlowFormSignParamBuildFactory;
import com.seeyon.apps.ext.workflow.vo.FieldDataVo;
import com.seeyon.apps.ext.workflow.vo.FormDataVo;
import com.seeyon.apps.ext.workflow.vo.SuperNodeContext;
import com.seeyon.cap4.form.bean.FormDataMasterBean;
import com.seeyon.ctp.common.AppContext;
import com.seeyon.ctp.common.exceptions.BusinessException;
import com.seeyon.utils.form.FormTableExecutor;
import com.seeyon.utils.form.FormUpdateField;
import com.seeyon.utils.form.FormWhereCondition;
import com.seeyon.utils.form.TableContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class EsignMultipleSignerNode extends ACommonSuperNode {
private static final Log log = LogFactory.getLog(EsignMultipleSignerNode.class);
private static final String CONTRACT_NAME_FIELD = "合同名称";
private static final String CONTRACT_ATTACHMENT_FIELD = "合同审批附件";
private static final String B_UNIT_NAME_FIELD = "乙方单位名称";
private EsignConfigProvider configProvider = EsignConfigProvider.getInstance();
// private EsignUploadFileService uploadFileService = (EsignUploadFileService) AppContext.getBean("esignByUploadFileService");
// private EsignByTemplateService templateService = (EsignByTemplateService) AppContext.getBean("esignByTemplateService");
// private FlowFormSignParamBuildFactory flowFormSignParamBuildFactory = new FlowFormSignParamBuildFactory();
private ContractCreateService contractCreateService = (ContractCreateService) AppContext.getBean("contractCreateService");
@Override
public String getPluginId() {
return EsignConfigConstants.getPluginId();
}
@Override
public String getFormParse() {
return "";
}
@Override
public SuperNodeContext proceed(String s, FormDataVo formDataVo, FormDataMasterBean formDataMasterBean) {
SuperNodeContext context = new SuperNodeContext();
context.setNeedSave(true);
log.info("进入E签宝多方签署集成超级节点");
try {
// Map<String, Object> signParams = buildSignParams(formDataVo, formDataMasterBean, true);
FlowParamSource source = new FlowParamSource();
source.setConfigProvider(configProvider);
source.setFormDataVo(formDataVo);
source.setDoAutoSign(true);
source.setMasterBean(formDataMasterBean);
String esignFlowId = contractCreateService.startSign(source);
if(esignFlowId == null) {
return context.back("E签宝签署发起失败");
}
log.info("E签宝签署流程ID: " + esignFlowId + " , OA超级节点ID" + formDataVo.getToken());
log.info("E签宝多方签署合同已发送: " + esignFlowId);
return context.wait("等待签署结束");
} catch (Exception e) {
log.error("E签宝签署失败", e);
context.setErrMsg("E签宝签署失败: " + e.getMessage());
return context.back("E签宝签署失败: " + e.getMessage());
}
}
// private Map<String, Object> buildSignFlowConfig(FormDataVo formDataVo,FormDataMasterBean masterBean) throws Exception {
// String contractName = getStringField(formDataVo, CONTRACT_NAME_FIELD);
// if (contractName == null) throw new RuntimeException("合同名称不能为空");
// String formId = formDataVo.getToken() +"_" + formDataVo.getId();
// Long enumId = masterBean.getFormTable().getFieldBeanByDisplay("E签宝签署状态").getEnumId();
// String signCallBackUrl = configProvider.getBizConfigByKey(EsignConfigConstants.OA_HOST) + "/seeyon/esigncallback.do?method=callback&formId=" + formId + "&tablename=" + masterBean.getFormTable().getTableName() + "&updatefield=" + masterBean.getFormTable().getFieldBeanByDisplay("盖章后合同附件").getColumnName() + "&statusfield=" + masterBean.getFormTable().getFieldBeanByDisplay("E签宝签署状态").getColumnName() + "_" + enumId;
// Map<String, Object> config = new HashMap<>();
// config.put("signFlowTitle", contractName);
// config.put("autoFinish", true);
// config.put("notifyUrl", signCallBackUrl);
// Map<String, Object> noticeConfig = new HashMap<>();
// noticeConfig.put("noticeTypes", "1");
// config.put("noticeConfig", noticeConfig);
// Map<String,Object> signConfig = new HashMap<>();
// signConfig.put("showBatchDropSealButton", false);
// config.put("signConfig",signConfig);
// return config;
// }
// private List<Signer> buildSigners(FormDataVo formDataVo, String fileId) throws Exception {
// List<String> keywords = new ArrayList<>();
// keywords.add("甲方盖章/签字");
// keywords.add("乙方盖章/签字");
// List<Object> positions = uploadFileService.getSignPosition(fileId,keywords);
// List<SignFieldPosition> bPositions = extractPosition(positions, "乙方盖章/签字");
// List<SignFieldPosition> aPositions = extractPosition(positions, "甲方盖章/签字");
// String bSignerType = formDataVo.getFieldData("乙方签署类型").getStringValue();
//
// SignFieldPosition aQiFengposition = new SignFieldPosition();
// aQiFengposition.setAcrossPageMode("ALL");
// aQiFengposition.setPositionY(520f);
// SignFieldPosition bQiFengposition = new SignFieldPosition();
// bQiFengposition.setAcrossPageMode("ALL");
// bQiFengposition.setPositionY(720f);
//
// aPositions.add(aQiFengposition);
// bPositions.add(bQiFengposition);
// String sealId = getStringField(formDataVo,"甲方印章ID");
// Signer bSigner = !"组织".equals(bSignerType) ? createPsnSigner(fileId,formDataVo.getFieldData("乙方姓名").getStringValue(),bPositions,1,formDataVo.getFieldData("乙方电话").getStringValue(),false) : createOrgSigner(
// fileId,
// getStringField(formDataVo, B_UNIT_NAME_FIELD),
// bPositions, 1, formDataVo.getFieldData("乙方法人姓名").getStringValue(),
// formDataVo.getFieldData("乙方法人身份证号").getStringValue(),
// formDataVo.getFieldData("乙方企业社会信用代码").getStringValue(),
// formDataVo.getFieldData("乙方经办人手机号").getStringValue(),
// formDataVo.getFieldData("乙方经办人姓名").getStringValue(),
// formDataVo.getFieldData("乙方经办人身份证号").getStringValue(),false
// ,null);
//
// Signer aSigner = createOrgSigner(
// fileId,null, aPositions, 2, null, null, null, null, null, null,true
// ,sealId);
// List<Signer> signers = new ArrayList<>();
// signers.add(bSigner);
// signers.add(aSigner);
// return signers;
// }
// private Map<String, Object> buildSignParams(FormDataVo formDataVo, FormDataMasterBean formDataMasterBean, boolean byFile) throws Exception {
//
// String fileId = null;
// if (byFile) {
// String attachmentId = getStringField(formDataVo, CONTRACT_ATTACHMENT_FIELD);
// if (attachmentId == null) throw new RuntimeException("合同附件不能为空");
// fileId = uploadFileService.uploadFileToEsign(attachmentId).get(0);
// }
// Map<String, Object> docMap = new HashMap<>();
// docMap.put("fileId", fileId);
// Thread.sleep(1000);
// List<Object> docs = new ArrayList<>();
// docs.add(docMap);
// Map<String, Object> signFlowConfig = buildSignFlowConfig(formDataVo, formDataMasterBean);
// List<Signer> signers = buildSigners(formDataVo, fileId);
// Map<String, Object> signParams = new HashMap<>();
// signParams.put("signFlowConfig", signFlowConfig);
// signParams.put("signers", signers);
// signParams.put("docs", docs);
// return signParams;
//
// }
//
// private void fillFileId(String fileId,FormDataVo formDataVo,FormDataMasterBean formDataMasterBean) throws NoSuchFieldException, BusinessException {
// TableContext tableContext = new TableContext(formDataMasterBean.getFormTable());
// List<FormUpdateField> updateFields = new ArrayList<>();
// updateFields.add(FormUpdateField.build().display("合同文件ID").value(fileId));
// List<FormWhereCondition> whereConditions = new ArrayList<>();
// whereConditions.add(FormWhereCondition.build().display("ID").value(formDataVo.getId()));
// FormTableExecutor.update(tableContext,updateFields,whereConditions);
// }
//
// private Map<String, Object> mapOf(Object... keyValues) {
// if (keyValues.length % 2 != 0) {
// throw new IllegalArgumentException("参数个数必须为偶数key 和 value 必须成对出现");
// }
// Map<String, Object> map = new HashMap<>();
// for (int i = 0; i < keyValues.length; i += 2) {
// Object key = keyValues[i];
// Object value = keyValues[i + 1];
// if (!(key instanceof String)) {
// throw new IllegalArgumentException("key 必须是 String 类型,当前为:" + key.getClass());
// }
// map.put((String) key, value);
// }
// return map;
// }
//
// private Signer createPsnSigner( String fileId, String psnName,List<SignFieldPosition> pos, int order, String phone,Boolean autoSign) {
// Signer signer = new Signer();
// signer.setSignerType(0);
// signer.setSignConfig(mapOf("signOrder", order));
// if(Boolean.FALSE.equals(autoSign)){
// signer.setNoticeConfig(mapOf("noticeTypes", "1"));
//
// Map<String, Object> psnInfo = mapOf("psnAccount", phone, "psnInfo", mapOf("psnName", psnName));
// signer.setPsnSignerInfo(psnInfo);
// }
//
// List<SignField> signFields = new ArrayList<>();
// for (SignFieldPosition po : pos) {
// NormalSignFieldConfig fieldConfig = new NormalSignFieldConfig();
// if("ALL".equals(po.getAcrossPageMode())){
// fieldConfig.setSignFieldPosition(po);
// fieldConfig.setAutoSign(autoSign);
// fieldConfig.setSignFieldStyle(2);
// SignField qiFengfield = new SignField();
// qiFengfield.setSignFieldType(0);
// qiFengfield.setNormalSignFieldConfig(fieldConfig);
// qiFengfield.setFileId(fileId);
// signFields.add(qiFengfield);
// }else {
// fieldConfig.setSignFieldPosition(po);
// fieldConfig.setAutoSign(autoSign);
// fieldConfig.setSignFieldStyle(1);
// SignField field = new SignField();
// field.setSignFieldType(0);
// field.setNormalSignFieldConfig(fieldConfig);
// field.setFileId(fileId);
// signFields.add(field);
// }
// }
//
// signer.setSignFields(signFields);
// return signer;
// }
//
// private Signer createOrgSigner(String fileId ,String orgName, List<SignFieldPosition> pos, int order,
// String legalName, String legalId, String orgCode,
// String transPhone, String psnName, String psnId,Boolean autoSign,String sealId) {
// Signer signer = new Signer();
// signer.setSignerType(1);
// signer.setSignConfig(mapOf("signOrder", order));
// if(Boolean.FALSE.equals(autoSign)){
// signer.setNoticeConfig(mapOf("noticeTypes", "1"));
//
// Map<String, Object> orgInfo = mapOf("orgName", orgName, "orgInfo", mapOf(
// "legalRepName", legalName,
// "legalRepIDCardNum", legalId,
// "orgIDCardNum", orgCode,
// "orgIDCardType", "CRED_ORG_USCC"
// ),
// "transactorInfo", mapOf(
// "psnAccount", transPhone,
// "psnInfo", mapOf(
// "psnName", psnName,
// "psnIDCardNum", psnId
// )
// )
// );
//
// signer.setOrgSignerInfo(orgInfo);
// }
//
// List<SignField> signFields = new ArrayList<>();
// for (SignFieldPosition po : pos) {
// NormalSignFieldConfig fieldConfig = new NormalSignFieldConfig();
// fieldConfig.setAssignedSealId(sealId);
// if("ALL".equals(po.getAcrossPageMode())){
// fieldConfig.setSignFieldPosition(po);
// fieldConfig.setAutoSign(autoSign);
// fieldConfig.setSignFieldStyle(2);
// SignField qiFengfield = new SignField();
// qiFengfield.setSignFieldType(0);
// qiFengfield.setNormalSignFieldConfig(fieldConfig);
// qiFengfield.setFileId(fileId);
// signFields.add(qiFengfield);
// }else {
// fieldConfig.setSignFieldPosition(po);
// fieldConfig.setAutoSign(autoSign);
// fieldConfig.setSignFieldStyle(1);
// SignField field = new SignField();
// field.setSignFieldType(0);
// field.setNormalSignFieldConfig(fieldConfig);
// field.setFileId(fileId);
// signFields.add(field);
// }
// }
//
// signer.setSignFields(signFields);
// return signer;
// }
//
// private List<SignFieldPosition> extractPosition(List<Object> positions, String keyword) {
// List<SignFieldPosition> posList = new ArrayList<>();
// for (Object obj : positions) {
// Map<String, Object> position = (Map<String, Object>) obj;
// if (Boolean.TRUE.equals(position.get("searchResult")) && keyword.equals(position.get("keyword"))) {
// Object[] posArray = (Object[]) position.get("positions");
// for (Object o : posArray) {
// Map<String, Object> posMap = (Map<String, Object>)o;
// Object[] coords = (Object[]) posMap.get("coordinates");
// for (Object coord : coords) {
// Map<String,Object> tempMap = (Map<String, Object>) coord;
// SignFieldPosition sfp = new SignFieldPosition();
// sfp.setPositionPage(posMap.get("pageNum") + "");
// sfp.setPositionX(toFloat(tempMap.get("positionX")) + 150f);
// sfp.setPositionY(toFloat(tempMap.get("positionY")));
// posList.add(sfp);
// }
// }
// return posList;
// }
// }
// throw new RuntimeException("未找到关键字位置: " + keyword);
// }
//
// private String getStringField(FormDataVo vo, String field) {
// try {
// FieldDataVo fieldData = vo.getFieldData(field);
// return fieldData.getStringValue();
// }catch (Exception e) {
// log.error(e.getMessage());
// return null;
// }
// }
//
// private Float toFloat(Object val) {
// return val instanceof Number ? ((Number) val).floatValue() : Float.parseFloat(val.toString());
// }
@Override
public String getNodeId() {
return "nd_20250703";
}
@Override
public String getNodeName() {
return "E签宝甲乙双方签署节点";
}
}

View File

@@ -0,0 +1,355 @@
package com.seeyon.apps.esign.node;
import com.seeyon.apps.common.workflow.node.ACommonSuperNode;
import com.seeyon.apps.esign.config.EsignConfigProvider;
import com.seeyon.apps.esign.constants.EsignConfigConstants;
import com.seeyon.apps.esign.po.param.FlowParamSource;
import com.seeyon.apps.esign.po.signer.Signer;
import com.seeyon.apps.esign.po.signfield.NormalSignFieldConfig;
import com.seeyon.apps.esign.po.signfield.SignField;
import com.seeyon.apps.esign.po.signfield.SignFieldPosition;
import com.seeyon.apps.esign.service.ContractCreateService;
import com.seeyon.apps.esign.service.EsignByTemplateService;
import com.seeyon.apps.esign.service.EsignUploadFileService;
import com.seeyon.apps.ext.workflow.vo.FieldDataVo;
import com.seeyon.apps.ext.workflow.vo.FormDataVo;
import com.seeyon.apps.ext.workflow.vo.SuperNodeContext;
import com.seeyon.cap4.form.bean.FormDataMasterBean;
import com.seeyon.cap4.form.service.CAP4FormManager;
import com.seeyon.ctp.common.AppContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.*;
public class EsignOneSignerNode extends ACommonSuperNode {
private static final Log log = LogFactory.getLog(EsignOneSignerNode.class);
private static final String CONTRACT_NAME_FIELD = "合同名称";
private static final String CONTRACT_ATTACHMENT_FIELD = "合同审批附件";
private static final String B_UNIT_NAME_FIELD = "乙方单位名称";
// @Autowired
// private EsignUploadFileService uploadFileService;
// @Autowired
// private EsignByTemplateService templateService;
private EsignConfigProvider configProvider = EsignConfigProvider.getInstance();
private ContractCreateService contractCreateService = (ContractCreateService) AppContext.getBean("contractCreateService");
@Override
public String getPluginId() {
return EsignConfigConstants.getPluginId();
}
@Override
public String getFormParse() {
return "";
}
@Override
public SuperNodeContext proceed(String s, FormDataVo formDataVo, FormDataMasterBean formDataMasterBean) {
SuperNodeContext context = new SuperNodeContext();
context.setNeedSave(true);
log.info("进入 E签宝单方签署集成超级节点");
try {
FlowParamSource source = new FlowParamSource();
source.setConfigProvider(configProvider);
source.setFormDataVo(formDataVo);
source.setDoAutoSign(false);
source.setMasterBean(formDataMasterBean);
String esignFlowId = contractCreateService.startSign(source);
if(esignFlowId == null) {
return context.back("E签宝签署发起失败");
}
log.info("E签宝签署流程ID: " + esignFlowId + " , OA超级节点ID" + formDataVo.getToken());
log.info("E签宝单方签署合同已发送: " + esignFlowId);
return context.wait("等待签署结束");
} catch (Exception e) {
log.error("E签宝签署失败", e);
context.setErrMsg("E签宝签署失败: " + e.getMessage());
return context.back("E签宝签署失败: " + e.getMessage());
}
}
// private Map<String, Object> buildSignFlowConfig(FormDataVo formDataVo,FormDataMasterBean masterBean) throws Exception {
// String contractName = getStringField(formDataVo, CONTRACT_NAME_FIELD);
// if (contractName == null) throw new RuntimeException("合同名称不能为空");
// String formId = formDataVo.getToken() +"_" + formDataVo.getId();
// Long enumId = masterBean.getFormTable().getFieldBeanByDisplay("E签宝签署状态").getEnumId();
// String signCallBackUrl = configProvider.getBizConfigByKey(EsignConfigConstants.OA_HOST) + "/seeyon/esigncallback.do?method=callback&formId=" + formId + "&tablename=" + masterBean.getFormTable().getTableName() + "&updatefield=" + masterBean.getFormTable().getFieldBeanByDisplay("盖章后合同附件").getColumnName() + "&statusfield=" + masterBean.getFormTable().getFieldBeanByDisplay("E签宝签署状态").getColumnName() + "_" + enumId;
// Map<String, Object> config = new HashMap<>();
// config.put("signFlowTitle", contractName);
// config.put("autoFinish", true);
// config.put("notifyUrl", signCallBackUrl);
// Map<String, Object> noticeConfig = new HashMap<>();
// noticeConfig.put("noticeTypes", "1");
// config.put("noticeConfig", noticeConfig);
// Map<String,Object> signConfig = new HashMap<>();
// signConfig.put("showBatchDropSealButton", false);
// config.put("signConfig",signConfig);
// return config;
// }
// private List<Signer> buildOnlyASigner(FormDataVo formDataVo, String fileId) throws Exception {
//
// SignFieldPosition aQiFengposition = new SignFieldPosition();
// aQiFengposition.setAcrossPageMode("ALL");
// aQiFengposition.setPositionY(520f);
// String sealId = getStringField(formDataVo,"甲方印章ID");
// String psnName = getStringField(formDataVo,"甲方签署经办人");
// String psnMobile = getStringField(formDataVo,"甲方签署经办人联系方式");
// String orgName = configProvider.getBizConfigByKey(EsignConfigConstants.UNITNAME);
// List<SignFieldPosition> pos = new ArrayList<>();
// Map<String, List<FormDataVo>> subFormMap = formDataVo.getSubFormMap();
// List<FormDataVo> subDataVos = subFormMap.get("甲方签署位置");
// Boolean autoSign = true;
// if(subDataVos!= null && subDataVos.size() > 0 && !subDataVos.get(0).isEmpty()){
// for (FormDataVo subDataVo : subDataVos) {
// Map<String, FieldDataVo> fieldDataVoMap = subDataVo.getFieldDataVoMap();
// String pageNo = fieldDataVoMap.get("页码").getStringValue();
// String positionX = fieldDataVoMap.get("X坐标").getStringValue();
// String positionY = fieldDataVoMap.get("Y坐标").getStringValue();
// SignFieldPosition position = new SignFieldPosition();
// position.setPositionPage(pageNo);
// position.setPositionX(Float.parseFloat(positionX));
// position.setPositionY(Float.parseFloat(positionY));
// pos.add(position);
// }
// pos.add(aQiFengposition);
// }else {
// autoSign = false;
// }
// Signer aSigner = createOrgSigner(
// fileId,orgName, pos, 1, null, null, null, psnMobile, psnName, null,autoSign
// ,sealId);
// List<Signer> signers = new ArrayList<>();
// signers.add(aSigner);
// return signers;
// }
// private Map<String, Object> buildSignParams(FormDataVo formDataVo, FormDataMasterBean formDataMasterBean, boolean byFile) throws Exception {
//
// String fileId = null;
// if (byFile) {
// String attachmentId = getStringField(formDataVo, CONTRACT_ATTACHMENT_FIELD);
// if (attachmentId == null) throw new RuntimeException("合同附件不能为空");
// fileId = uploadFileService.uploadFileToEsign(attachmentId).get(0);
// }
// Map<String, Object> docMap = new HashMap<>();
// Thread.sleep(1000);
// docMap.put("fileId", fileId);
// List<Object> docs = new ArrayList<>();
// docs.add(docMap);
// Map<String, Object> signFlowConfig = buildSignFlowConfig(formDataVo, formDataMasterBean);
// List<Signer> signers = buildOnlyASigner(formDataVo, fileId);
// Map<String, Object> signParams = new HashMap<>();
// signParams.put("signFlowConfig", signFlowConfig);
// signParams.put("signers", signers);
// signParams.put("docs", docs);
// return signParams;
//
// }
// private Map<String, Object> mapOf(Object... keyValues) {
// if (keyValues.length % 2 != 0) {
// throw new IllegalArgumentException("参数个数必须为偶数key 和 value 必须成对出现");
// }
// Map<String, Object> map = new HashMap<>();
// for (int i = 0; i < keyValues.length; i += 2) {
// Object key = keyValues[i];
// Object value = keyValues[i + 1];
// if (!(key instanceof String)) {
// throw new IllegalArgumentException("key 必须是 String 类型,当前为:" + key.getClass());
// }
// map.put((String) key, value);
// }
// return map;
// }
//
// private Signer createPsnSigner( String fileId, String psnName,List<SignFieldPosition> pos, int order, String phone,Boolean autoSign) {
// Signer signer = new Signer();
// signer.setSignerType(0);
// signer.setSignConfig(mapOf("signOrder", order));
// if(Boolean.FALSE.equals(autoSign)){
// signer.setNoticeConfig(mapOf("noticeTypes", "1"));
//
// Map<String, Object> psnInfo = mapOf("psnAccount", phone, "psnInfo", mapOf("psnName", psnName));
// signer.setPsnSignerInfo(psnInfo);
// }
//
// List<SignField> signFields = new ArrayList<>();
// for (SignFieldPosition po : pos) {
// NormalSignFieldConfig fieldConfig = new NormalSignFieldConfig();
// if("ALL".equals(po.getAcrossPageMode())){
// fieldConfig.setSignFieldPosition(po);
// fieldConfig.setAutoSign(autoSign);
// fieldConfig.setSignFieldStyle(2);
// SignField qiFengfield = new SignField();
// qiFengfield.setSignFieldType(0);
// qiFengfield.setNormalSignFieldConfig(fieldConfig);
// qiFengfield.setFileId(fileId);
// signFields.add(qiFengfield);
// }else {
// fieldConfig.setSignFieldPosition(po);
// fieldConfig.setAutoSign(autoSign);
// fieldConfig.setSignFieldStyle(1);
// SignField field = new SignField();
// field.setSignFieldType(0);
// field.setNormalSignFieldConfig(fieldConfig);
// field.setFileId(fileId);
// signFields.add(field);
// }
// }
//
// signer.setSignFields(signFields);
// return signer;
// }
//
// private Signer createOrgSigner(String fileId ,String orgName, List<SignFieldPosition> pos, int order,
// String legalName, String legalId, String orgCode,
// String transPhone, String psnName, String psnId,Boolean autoSign,String sealId) {
// Signer signer = new Signer();
// signer.setSignerType(1);
// signer.setSignConfig(mapOf("signOrder", order));
// List<SignField> signFields = new ArrayList<>();
// signer.setSignFields(signFields);
// if(Boolean.FALSE.equals(autoSign)){
// signer.setNoticeConfig(mapOf("noticeTypes", "1"));
//
// Map<String, Object> orgInfo = mapOf("orgName", orgName,
// "transactorInfo", mapOf(
// "psnAccount", transPhone,
// "psnInfo", mapOf(
// "psnName", psnName
// )
// )
// );
// signer.setOrgSignerInfo(orgInfo);
// NormalSignFieldConfig normalSignFieldConfig = new NormalSignFieldConfig();
// normalSignFieldConfig.setAssignedSealId(sealId);
// normalSignFieldConfig.setFreeMode(true);
// normalSignFieldConfig.setAutoSign(false);
// normalSignFieldConfig.setAdaptableSignFieldSize(true);
// SignField field = new SignField();
// field.setSignFieldType(0);
// field.setNormalSignFieldConfig(normalSignFieldConfig);
// field.setFileId(fileId);
// signFields.add(field);
// }else {
// for (SignFieldPosition po : pos) {
// NormalSignFieldConfig fieldConfig = new NormalSignFieldConfig();
// fieldConfig.setAssignedSealId(sealId);
// fieldConfig.setAutoSign(autoSign);
// if("ALL".equals(po.getAcrossPageMode())){
// fieldConfig.setSignFieldPosition(po);
// fieldConfig.setSignFieldStyle(2);
// SignField qiFengfield = new SignField();
// qiFengfield.setSignFieldType(0);
// qiFengfield.setNormalSignFieldConfig(fieldConfig);
// qiFengfield.setFileId(fileId);
// signFields.add(qiFengfield);
// }else {
// fieldConfig.setSignFieldPosition(po);
// fieldConfig.setSignFieldStyle(1);
// SignField field = new SignField();
// field.setSignFieldType(0);
// field.setNormalSignFieldConfig(fieldConfig);
// field.setFileId(fileId);
// signFields.add(field);
// }
// }
// }
// return signer;
// }
//
// private Signer createOrgQiFengSigner(String fileId ,String orgName, SignFieldPosition po, int order,
// String legalName, String legalId, String orgCode,
// String transPhone, String psnName, String psnId,Boolean autoSign,String sealId) {
// Signer signer = new Signer();
// signer.setSignerType(1);
// signer.setSignConfig(mapOf("signOrder", order));
// if(Boolean.FALSE.equals(autoSign)){
// signer.setNoticeConfig(mapOf("noticeTypes", "1"));
//
// Map<String, Object> orgInfo = mapOf("orgName", orgName,
// "transactorInfo", mapOf(
// "psnAccount", transPhone,
// "psnInfo", mapOf(
// "psnName", psnName
// )
// )
// );
//
// signer.setOrgSignerInfo(orgInfo);
// }
//
// List<SignField> signFields = new ArrayList<>();
//
// NormalSignFieldConfig normalSignFieldConfig = new NormalSignFieldConfig();
// normalSignFieldConfig.setAssignedSealId(sealId);
//
// normalSignFieldConfig.setSignFieldPosition(po);
// normalSignFieldConfig.setAutoSign(autoSign);
// normalSignFieldConfig.setSignFieldStyle(2);
// SignField qiFengfield = new SignField();
// qiFengfield.setSignFieldType(0);
// qiFengfield.setNormalSignFieldConfig(normalSignFieldConfig);
// qiFengfield.setFileId(fileId);
// signFields.add(qiFengfield);
//
// signer.setSignFields(signFields);
// return signer;
// }
//
//
// private List<SignFieldPosition> extractPosition(List<Object> positions, String keyword) {
// List<SignFieldPosition> posList = new ArrayList<>();
// for (Object obj : positions) {
// Map<String, Object> position = (Map<String, Object>) obj;
// if (Boolean.TRUE.equals(position.get("searchResult")) && keyword.equals(position.get("keyword"))) {
// Object[] posArray = (Object[]) position.get("positions");
// for (Object o : posArray) {
// Map<String, Object> posMap = (Map<String, Object>)o;
// Object[] coords = (Object[]) posMap.get("coordinates");
// for (Object coord : coords) {
// Map<String,Object> tempMap = (Map<String, Object>) coord;
// SignFieldPosition sfp = new SignFieldPosition();
// sfp.setPositionPage(posMap.get("pageNum") + "");
// sfp.setPositionX(toFloat(tempMap.get("positionX")) + 150f);
// sfp.setPositionY(toFloat(tempMap.get("positionY")));
// posList.add(sfp);
// }
// }
// return posList;
// }
// }
// throw new RuntimeException("未找到关键字位置: " + keyword);
// }
//
// private String getStringField(FormDataVo vo, String field) {
// try {
// FieldDataVo fieldData = vo.getFieldData(field);
// return fieldData.getStringValue();
// }catch (Exception e) {
// log.error(e.getMessage());
// return null;
// }
// }
//
// private Float toFloat(Object val) {
// return val instanceof Number ? ((Number) val).floatValue() : Float.parseFloat(val.toString());
// }
@Override
public String getNodeId() {
return "nd_20250702";
}
@Override
public String getNodeName() {
return "E签宝甲方单方签署节点";
}
}

View File

@@ -0,0 +1,38 @@
package com.seeyon.apps.esign.node;
import com.seeyon.apps.common.workflow.node.ACommonSuperNode;
import com.seeyon.apps.ext.workflow.vo.FormDataVo;
import com.seeyon.apps.ext.workflow.vo.SuperNodeContext;
import com.seeyon.cap4.form.bean.FormDataMasterBean;
public class EsignOrgAuthNode extends ACommonSuperNode {
@Override
public String getPluginId() {
return "";
}
@Override
public String getFormParse() {
return "";
}
@Override
public SuperNodeContext proceed(String s, FormDataVo formDataVo, FormDataMasterBean formDataMasterBean) throws Exception {
//个人实名认证、企业认证处理
return null;
}
public void personAuth() {
// /v3/psn-auth-url
}
@Override
public String getNodeId() {
return "";
}
@Override
public String getNodeName() {
return "";
}
}

View File

@@ -0,0 +1,56 @@
package com.seeyon.apps.esign.node;
import com.seeyon.apps.common.workflow.node.ACommonSuperNode;
import com.seeyon.apps.esign.po.auth.AuthPsnInfo;
import com.seeyon.apps.esign.po.auth.PsnAuthConfig;
import com.seeyon.apps.ext.workflow.vo.FormDataVo;
import com.seeyon.apps.ext.workflow.vo.SuperNodeContext;
import com.seeyon.cap4.form.bean.FormDataMasterBean;
import java.util.HashMap;
import java.util.Map;
public class EsignPersonAuthNode extends ACommonSuperNode {
@Override
public String getPluginId() {
return "";
}
@Override
public String getFormParse() {
return "";
}
@Override
public SuperNodeContext proceed(String s, FormDataVo formDataVo, FormDataMasterBean formDataMasterBean) throws Exception {
Map<String,Object> authParams = new HashMap<>();
PsnAuthConfig psnAuthConfig = buildPsnAuthConfig(formDataVo,formDataMasterBean);
String notifyUrl= "";
authParams.put("psnAuthConfig",psnAuthConfig);
authParams.put("notifyUrl",notifyUrl);
return null;
}
private PsnAuthConfig buildPsnAuthConfig(FormDataVo formDataVo, FormDataMasterBean formDataMasterBean) throws Exception {
PsnAuthConfig psnAuthConfig = new PsnAuthConfig();
psnAuthConfig.setPsnAccount(formDataVo.getFieldData("客户联系电话").getStringValue());
AuthPsnInfo authPsnInfo = new AuthPsnInfo();
authPsnInfo.setPsnName(formDataVo.getFieldData("客户联系人姓名").getStringValue());
authPsnInfo.setPsnMobile(formDataVo.getFieldData("客户联系电话").getStringValue());
authPsnInfo.setPsnIDCardType("CRED_PSN_CH_IDCARD");
authPsnInfo.setPsnIDCardNum(formDataVo.getFieldData("客户身份证号").getStringValue());
authPsnInfo.setPsnIdentityVerify(true);
return psnAuthConfig;
}
@Override
public String getNodeId() {
return "";
}
@Override
public String getNodeName() {
return "";
}
}

View File

@@ -0,0 +1,61 @@
package com.seeyon.apps.esign.po.auth;
import com.fasterxml.jackson.annotation.JsonInclude;
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class AuthPsnInfo {
private String psnName;
private String psnIDCardNum;
private String psnIDCardType;
private String psnMobile;
private String bankCardNum;
private Boolean psnIdentityVerify;
public String getPsnName() {
return psnName;
}
public void setPsnName(String psnName) {
this.psnName = psnName;
}
public String getPsnIDCardNum() {
return psnIDCardNum;
}
public void setPsnIDCardNum(String psnIDCardNum) {
this.psnIDCardNum = psnIDCardNum;
}
public String getPsnIDCardType() {
return psnIDCardType;
}
public void setPsnIDCardType(String psnIDCardType) {
this.psnIDCardType = psnIDCardType;
}
public String getPsnMobile() {
return psnMobile;
}
public void setPsnMobile(String psnMobile) {
this.psnMobile = psnMobile;
}
public String getBankCardNum() {
return bankCardNum;
}
public void setBankCardNum(String bankCardNum) {
this.bankCardNum = bankCardNum;
}
public Boolean getPsnIdentityVerify() {
return psnIdentityVerify;
}
public void setPsnIdentityVerify(Boolean psnIdentityVerify) {
this.psnIdentityVerify = psnIdentityVerify;
}
}

View File

@@ -0,0 +1,40 @@
package com.seeyon.apps.esign.po.auth;
public class PsnAuthConfig {
private String psnAccount;
private String psnId;
private AuthPsnInfo psnInfo;
private PsnAuthPageConfig psnAuthPageConfig;
public String getPsnAccount() {
return psnAccount;
}
public void setPsnAccount(String psnAccount) {
this.psnAccount = psnAccount;
}
public String getPsnId() {
return psnId;
}
public void setPsnId(String psnId) {
this.psnId = psnId;
}
public AuthPsnInfo getPsnInfo() {
return psnInfo;
}
public void setPsnInfo(AuthPsnInfo psnInfo) {
this.psnInfo = psnInfo;
}
public PsnAuthPageConfig getPsnAuthPageConfig() {
return psnAuthPageConfig;
}
public void setPsnAuthPageConfig(PsnAuthPageConfig psnAuthPageConfig) {
this.psnAuthPageConfig = psnAuthPageConfig;
}
}

View File

@@ -0,0 +1,45 @@
package com.seeyon.apps.esign.po.auth;
import com.fasterxml.jackson.annotation.JsonInclude;
import java.util.List;
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class PsnAuthPageConfig {
private String psnDefaultAuthMode;
private List<String> psnAvailableAuthModes;
private List<String> advancedVersion;
private List<String> psnEditableFields;
public String getPsnDefaultAuthMode() {
return psnDefaultAuthMode;
}
public void setPsnDefaultAuthMode(String psnDefaultAuthMode) {
this.psnDefaultAuthMode = psnDefaultAuthMode;
}
public List<String> getPsnAvailableAuthModes() {
return psnAvailableAuthModes;
}
public void setPsnAvailableAuthModes(List<String> psnAvailableAuthModes) {
this.psnAvailableAuthModes = psnAvailableAuthModes;
}
public List<String> getAdvancedVersion() {
return advancedVersion;
}
public void setAdvancedVersion(List<String> advancedVersion) {
this.advancedVersion = advancedVersion;
}
public List<String> getPsnEditableFields() {
return psnEditableFields;
}
public void setPsnEditableFields(List<String> psnEditableFields) {
this.psnEditableFields = psnEditableFields;
}
}

View File

@@ -0,0 +1,219 @@
package com.seeyon.apps.esign.po.esignapi;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
public class EsignApiHeader {
private String xTsignOpenAppId;
private String xTsignOpenAuthMode;
private String xTsignOpenCaSignature;
private String xTsignOpenCaTimestamp;
private String accept;
private String contentType = "application/json; charset=UTF-8";
private String contentMd5;
private String httpMethod;
private String date;
private String headers;
private String pathAndParameters;
private String token;
public String getxTsignOpenAppId() {
return xTsignOpenAppId;
}
public void setxTsignOpenAppId(String xTsignOpenAppId) {
this.xTsignOpenAppId = xTsignOpenAppId;
}
public String getX_Tsign_Open_Auth_Mode() {
return xTsignOpenAuthMode;
}
public void setX_Tsign_Open_Auth_Mode(String x_Tsign_Open_Auth_Mode) {
this.xTsignOpenAuthMode = x_Tsign_Open_Auth_Mode;
}
public String getxTsignOpenCaSignature() {
return xTsignOpenCaSignature;
}
public void setxTsignOpenCaSignature(String xTsignOpenCaSignature) {
this.xTsignOpenCaSignature = xTsignOpenCaSignature;
}
public String getxTsignOpenCaTimestamp() {
return xTsignOpenCaTimestamp;
}
public void setxTsignOpenCaTimestamp(String xTsignOpenCaTimestamp) {
this.xTsignOpenCaTimestamp = xTsignOpenCaTimestamp;
}
public String getAccept() {
return accept;
}
public void setAccept(String accept) {
this.accept = accept;
}
public String getContentType() {
return contentType;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
public String getContentMd5() {
return contentMd5;
}
public void setContentMd5(String contentMd5) {
this.contentMd5 = contentMd5;
}
public static EsignApiHeader build() {
EsignApiHeader header = new EsignApiHeader();
header.setAccept("*/*");
header.setX_Tsign_Open_Auth_Mode("Signature");
return header;
}
public EsignApiHeader pathAndParameters(String pathAndParameters) {
this.pathAndParameters = pathAndParameters;
return this;
}
public EsignApiHeader appId(String appId) {
this.xTsignOpenAppId = appId;
return this;
}
public EsignApiHeader heads(String headers) {
this.headers = headers;
return this;
}
public EsignApiHeader timeStamp() {
this.xTsignOpenCaTimestamp = System.currentTimeMillis() + "";
return this;
}
public EsignApiHeader token(String token) {
this.token = token;
return this;
}
public EsignApiHeader contentMD5(String body) {
this.contentMd5 = getBodyContentMD5(body);
return this;
}
public EsignApiHeader httpMethod(String httpMethod) {
this.httpMethod = httpMethod;
return this;
}
public EsignApiHeader signature(String secret) throws Exception {
StringBuffer strBuff = new StringBuffer();
strBuff.append(httpMethod).append("\n").append(accept).append("\n").append(contentMd5).append("\n")
.append(contentType).append("\n").append("").append("\n");
if ("".equals(headers)) {
strBuff.append(headers).append(pathAndParameters);
} else {
strBuff.append(headers).append("\n").append(pathAndParameters);
}
String StringToSign = strBuff.toString();
this.setxTsignOpenCaSignature(doSignatureBase64(StringToSign, secret));
return this;
}
public String doSignatureBase64(String message, String secret) throws Exception {
String algorithm = "HmacSHA256";
Mac hmacSha256;
String digestBase64 = null;
try {
hmacSha256 = Mac.getInstance(algorithm);
byte[] keyBytes = secret.getBytes("UTF-8");
byte[] messageBytes = message.getBytes("UTF-8");
hmacSha256.init(new SecretKeySpec(keyBytes, 0, keyBytes.length, algorithm));
// 使用HmacSHA256对二进制数据消息Bytes计算摘要
byte[] digestBytes = hmacSha256.doFinal(messageBytes);
// 把摘要后的结果digestBytes使用Base64进行编码
digestBase64 = new String(Base64.encodeBase64(digestBytes), "UTF-8");
} catch (NoSuchAlgorithmException e) {
String msg = MessageFormat.format("不支持此算法: {0}", e.getMessage());
Exception ex = new Exception(msg);
ex.initCause(e);
throw ex;
} catch (UnsupportedEncodingException e) {
String msg = MessageFormat.format("不支持的字符编码: {0}", e.getMessage());
Exception ex = new Exception(msg);
ex.initCause(e);
throw ex;
} catch (InvalidKeyException e) {
String msg = MessageFormat.format("无效的密钥规范: {0}", e.getMessage());
Exception ex = new Exception(msg);
ex.initCause(e);
throw ex;
}
return digestBase64;
}
/***
* 计算请求Body体的Content-MD5
* @param bodyData 请求Body体数据
* @return
*/
public String getBodyContentMD5(String bodyData) {
if("".equals(bodyData)) {
return bodyData;
}
// 获取Body体的MD5的二进制数组128位
byte[] bytes = getBodyMD5Bytes128(bodyData);
// 对Body体MD5的二进制数组进行Base64编码
return new String(Base64.encodeBase64(bytes));
}
public byte[] getBodyMD5Bytes128(String bodyData) {
byte[] md5Bytes = null;
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(bodyData.getBytes(StandardCharsets.UTF_8));
md5Bytes = md5.digest();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return md5Bytes;
}
public Map<String,String> convert2Headers(){
Map<String,String> headers = new HashMap<>();
if(xTsignOpenAppId != null) {
headers.put("X-Tsign-Open-App-Id", xTsignOpenAppId);
}
if(token != null) {
headers.put("X-Tsign-Open-Token", token);
}
if(contentType != null) {
headers.put("Content-Type", contentType);
}
if(!StringUtils.isBlank(contentMd5)) {
headers.put("Content-MD5", contentMd5);
}
return headers;
}
}

View File

@@ -0,0 +1,31 @@
package com.seeyon.apps.esign.po.esignapi;
public class EsignBaseResp {
private int code;
private String message;
private Object data;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}

View File

@@ -0,0 +1,65 @@
package com.seeyon.apps.esign.po.esignapi;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import java.io.Serializable;
@JsonIgnoreProperties(ignoreUnknown = true)
public class EsignCallbackParams implements Serializable {
private String signFlowId;
private String action;
private String resultDescription; //签署结果描述
private Integer signResult; //签署结果
private Integer signFlowStatus; //签署流程状态
private Integer signOrder; //签署顺序
public String getSignFlowId() {
return signFlowId;
}
public void setSignFlowId(String signFlowId) {
this.signFlowId = signFlowId;
}
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
public String getResultDescription() {
return resultDescription;
}
public void setResultDescription(String resultDescription) {
this.resultDescription = resultDescription;
}
public Integer getSignResult() {
return signResult;
}
public void setSignResult(Integer signResult) {
this.signResult = signResult;
}
public Integer getSignFlowStatus() {
return signFlowStatus;
}
public void setSignFlowStatus(Integer signFlowStatus) {
this.signFlowStatus = signFlowStatus;
}
public Integer getSignOrder() {
return signOrder;
}
public void setSignOrder(Integer signOrder) {
this.signOrder = signOrder;
}
}

View File

@@ -0,0 +1,36 @@
package com.seeyon.apps.esign.po.esignapi;
/**
* description 自定义全局异常
* @author 澄泓
* datetime 2019年7月1日上午10:43:24
*/
public class EsignException extends Exception {
private static final long serialVersionUID = 4359180081622082792L;
private Exception e;
public EsignException(String msg) {
super(msg);
}
public EsignException(String msg, Throwable cause) {
super(msg,cause);
}
public EsignException(){
}
public Exception getE() {
return e;
}
public void setE(Exception e) {
this.e = e;
}
}

View File

@@ -0,0 +1,27 @@
package com.seeyon.apps.esign.po.esignapi;
/**
* 网络请求的response类
* @author 澄泓
* @date 2022/2/21 17:28
* @version
*/
public class EsignHttpResponse {
private int status;
private String body;
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
}

View File

@@ -0,0 +1,34 @@
package com.seeyon.apps.esign.po.esignapi;
import java.io.Serializable;
public class EsignToken implements Serializable {
private String tokenStr;
private Long ttl;
private String refreshToken;
public String getTokenStr() {
return tokenStr;
}
public void setTokenStr(String tokenStr) {
this.tokenStr = tokenStr;
}
public Long getTtl() {
return ttl;
}
public void setTtl(Long ttl) {
this.ttl = ttl;
}
public String getRefreshToken() {
return refreshToken;
}
public void setRefreshToken(String refreshToken) {
this.refreshToken = refreshToken;
}
}

View File

@@ -0,0 +1,22 @@
package com.seeyon.apps.esign.po.file;
public class SignFile {
private String fileName;
private String fileId;
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public String getFileId() {
return fileId;
}
public void setFileId(String fileId) {
this.fileId = fileId;
}
}

View File

@@ -0,0 +1,31 @@
package com.seeyon.apps.esign.po.file;
public class TemplateComponent {
private String componentId;
private String componentKey;
private String componentValue;
public String getComponentId() {
return componentId;
}
public void setComponentId(String componentId) {
this.componentId = componentId;
}
public String getComponentKey() {
return componentKey;
}
public void setComponentKey(String componentKey) {
this.componentKey = componentKey;
}
public String getComponentValue() {
return componentValue;
}
public void setComponentValue(String componentValue) {
this.componentValue = componentValue;
}
}

View File

@@ -0,0 +1,22 @@
package com.seeyon.apps.esign.po.file;
public class TemplateInfo {
private String signTemplateName;
private String signTemplateId;
public String getSignTemplateName() {
return signTemplateName;
}
public void setSignTemplateName(String signTemplateName) {
this.signTemplateName = signTemplateName;
}
public String getSignTemplateId() {
return signTemplateId;
}
public void setSignTemplateId(String signTemplateId) {
this.signTemplateId = signTemplateId;
}
}

View File

@@ -0,0 +1,39 @@
package com.seeyon.apps.esign.po.flow;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.seeyon.apps.esign.po.org.OrgInitiator;
import com.seeyon.apps.esign.po.personal.PsnInitiator;
import java.util.List;
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class SignFlowInitiator {
private OrgInitiator orgInitiator;
private PsnInitiator psnInitiator;
private List<String> initialRemarks;
public PsnInitiator getPsnInitiator() {
return psnInitiator;
}
public void setPsnInitiator(PsnInitiator psnInitiator) {
this.psnInitiator = psnInitiator;
}
public List<String> getInitialRemarks() {
return initialRemarks;
}
public void setInitialRemarks(List<String> initialRemarks) {
this.initialRemarks = initialRemarks;
}
public OrgInitiator getOrgInitiator() {
return orgInitiator;
}
public void setOrgInitiator(OrgInitiator orgInitiator) {
this.orgInitiator = orgInitiator;
}
}

View File

@@ -0,0 +1,22 @@
package com.seeyon.apps.esign.po.org;
public class OrgInitiator {
private String orgId;
private Transactor transactor;
public String getOrgId() {
return orgId;
}
public void setOrgId(String orgId) {
this.orgId = orgId;
}
public Transactor getTransactor() {
return transactor;
}
public void setTransactor(Transactor transactor) {
this.transactor = transactor;
}
}

View File

@@ -0,0 +1,127 @@
package com.seeyon.apps.esign.po.org;
import com.fasterxml.jackson.annotation.JsonInclude;
import java.util.List;
import java.util.Map;
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class SignFlowConfig {
private String signFlowTitle;
private Long signFlowExpireTime;
private Boolean autoStart;
private Boolean autoFinish;
private Boolean identifyVerify;
private String notifyUrl;
private Map<String,Object> redirectConfig;
private Map<String,Object> signConfig;
private Map<String,Object> noticeConfig;
private Map<String,Object> authConfig;
private Map<String,Object> contractConfig;
private List<String> contractGroupIds;
private Boolean docsViewLimited;
public String getSignFlowTitle() {
return signFlowTitle;
}
public void setSignFlowTitle(String signFlowTitle) {
this.signFlowTitle = signFlowTitle;
}
public Long getSignFlowExpireTime() {
return signFlowExpireTime;
}
public void setSignFlowExpireTime(Long signFlowExpireTime) {
this.signFlowExpireTime = signFlowExpireTime;
}
public Boolean getAutoStart() {
return autoStart;
}
public void setAutoStart(Boolean autoStart) {
this.autoStart = autoStart;
}
public Boolean getAutoFinish() {
return autoFinish;
}
public void setAutoFinish(Boolean autoFinish) {
this.autoFinish = autoFinish;
}
public Boolean getIdentifyVerify() {
return identifyVerify;
}
public void setIdentifyVerify(Boolean identifyVerify) {
this.identifyVerify = identifyVerify;
}
public String getNotifyUrl() {
return notifyUrl;
}
public void setNotifyUrl(String notifyUrl) {
this.notifyUrl = notifyUrl;
}
public Map<String, Object> getRedirectConfig() {
return redirectConfig;
}
public void setRedirectConfig(Map<String, Object> redirectConfig) {
this.redirectConfig = redirectConfig;
}
public Map<String, Object> getSignConfig() {
return signConfig;
}
public void setSignConfig(Map<String, Object> signConfig) {
this.signConfig = signConfig;
}
public Map<String, Object> getNoticeConfig() {
return noticeConfig;
}
public void setNoticeConfig(Map<String, Object> noticeConfig) {
this.noticeConfig = noticeConfig;
}
public Map<String, Object> getAuthConfig() {
return authConfig;
}
public void setAuthConfig(Map<String, Object> authConfig) {
this.authConfig = authConfig;
}
public Map<String, Object> getContractConfig() {
return contractConfig;
}
public void setContractConfig(Map<String, Object> contractConfig) {
this.contractConfig = contractConfig;
}
public List<String> getContractGroupIds() {
return contractGroupIds;
}
public void setContractGroupIds(List<String> contractGroupIds) {
this.contractGroupIds = contractGroupIds;
}
public Boolean getDocsViewLimited() {
return docsViewLimited;
}
public void setDocsViewLimited(Boolean docsViewLimited) {
this.docsViewLimited = docsViewLimited;
}
}

View File

@@ -0,0 +1,13 @@
package com.seeyon.apps.esign.po.org;
public class Transactor {
private String psnId;
public String getPsnId() {
return psnId;
}
public void setPsnId(String psnId) {
this.psnId = psnId;
}
}

View File

@@ -0,0 +1,197 @@
package com.seeyon.apps.esign.po.param;
import com.seeyon.apps.esign.config.EsignConfigProvider;
import com.seeyon.apps.esign.constants.EsignConfigConstants;
import com.seeyon.apps.esign.po.signer.*;
import com.seeyon.apps.esign.service.SignParamSource;
import com.seeyon.apps.ext.workflow.vo.FieldDataVo;
import com.seeyon.apps.ext.workflow.vo.FormDataVo;
import com.seeyon.cap4.form.bean.FormDataMasterBean;
import com.seeyon.utils.form.EnumMapUtils;
import java.util.ArrayList;
import java.util.List;
public class FlowParamSource implements SignParamSource {
private FormDataVo formDataVo;
private FormDataMasterBean masterBean;
private Boolean doAutoSign = false;
private EsignConfigProvider configProvider;
private String callbackBaseUrl;
public FormDataVo getFormDataVo() {
return formDataVo;
}
public void setFormDataVo(FormDataVo formDataVo) {
this.formDataVo = formDataVo;
}
public FormDataMasterBean getMasterBean() {
return masterBean;
}
public void setMasterBean(FormDataMasterBean masterBean) {
this.masterBean = masterBean;
}
public FlowParamSource(){}
public FlowParamSource(FormDataVo formDataVo, FormDataMasterBean masterBean){
this.formDataVo = formDataVo;
this.masterBean = masterBean;
}
public Boolean getDoAutoSign() {
return doAutoSign;
}
public void setDoAutoSign(Boolean doAutoSign) {
this.doAutoSign = doAutoSign;
}
@Override
public String getContractTitle() {
return getStringField(formDataVo,"合同名称");
}
@Override
public boolean isByFile() {
return true;
}
@Override
public String getBizFormId() {
return formDataVo.getToken() +"_" + formDataVo.getId();
}
@Override
public String getTableName() {
return masterBean.getFormTable().getTableName();
}
@Override
public String getSignFileRefId() {
return getStringField(formDataVo,"合同审批附件");
}
@Override
public String getSignedFileField() {
return masterBean.getFormTable().getFieldBeanByDisplay("盖章后合同附件").getColumnName();
}
@Override
public String getSignStatusField() {
return masterBean.getFormTable().getFieldBeanByDisplay("签署状态").getColumnName();
}
@Override
public Long getSignStatusEnumId() {
return masterBean.getFormTable().getFieldBeanByDisplay("签署状态").getEnumId();
}
@Override
public boolean autoSign() {
return doAutoSign;
}
@Override
public String getCallbackUrl() {
return getCallbackBaseUrl() + "&formId=" + getBizFormId() +
"&tablename=" + getTableName() +
"&updatefield=" + getSignedFileField() +
"&statusfield=" + getSignStatusField() + "_" + getSignStatusEnumId() +
"&bizType=FLOW";
}
@Override
public List<SignParty> getSignerParties() {
List<SignParty> parties = new ArrayList<>();
SignParty aParty = new SignParty();
aParty.setPartyId("甲方");
aParty.setAutoSign(autoSign());
aParty.setSignOrder(2);
aParty.setSignerType(SignerType.ORG);
aParty.setSealId(getStringField(formDataVo,"甲方印章ID"));
if(!doAutoSign){
OrgInfo orgInfo = new OrgInfo();
aParty.setOrgInfo(orgInfo);
String psnName = getStringField(formDataVo,"甲方签署经办人");
String psnMobile = getStringField(formDataVo,"甲方签署经办人联系方式");
String orgName = configProvider.getBizConfigByKey(EsignConfigConstants.UNITNAME);
PersonInfo personInfo = new PersonInfo();
orgInfo.setOrgName(orgName);
personInfo.setName(psnName);
personInfo.setPhone(psnMobile);
orgInfo.setTransactor(personInfo);
}
parties.add(aParty);
String signWay = getStringField(formDataVo, "签署方式");
String signWayText = null;
try {
signWayText = EnumMapUtils.getEnumShowValue(signWay);
}catch (Exception e) {}
if(!"甲方线上,乙方线下".equals(signWayText)){
SignParty bParty = new SignParty();
bParty.setPartyId("乙方");
bParty.setSignOrder(1);
try {
String bSignerType = formDataVo.getFieldData("乙方签署类型").getStringValue();
if(!"组织".equals(bSignerType)) {
PersonInfo bPersonInfo = new PersonInfo();
bPersonInfo.setPhone(getStringField(formDataVo,"乙方电话"));
bPersonInfo.setName(getStringField(formDataVo,"乙方姓名"));
bParty.setPersonInfo(bPersonInfo);
bParty.setSignerType(SignerType.PERSON);
}else {
OrgInfo bOrgInfo = new OrgInfo();
bOrgInfo.setLegalName(getStringField(formDataVo,"乙方法人姓名"));
bOrgInfo.setOrgName(getStringField(formDataVo,"乙方单位名称"));
bOrgInfo.setOrgCode(getStringField(formDataVo,"乙方统一社会信用代码"));
bOrgInfo.setLegalIdCardNo(getStringField(formDataVo,"乙方法人身份证号"));
PersonInfo transactor = new PersonInfo();
transactor.setName(getStringField(formDataVo,"乙方经办人姓名"));
transactor.setIdCardNo(getStringField(formDataVo,"乙方经办人身份证号"));
transactor.setPhone(getStringField(formDataVo,"乙方经办人手机号"));
bOrgInfo.setTransactor(transactor);
bParty.setOrgInfo(bOrgInfo);
bParty.setSignerType(SignerType.ORG);
}
}catch (Exception e){}
parties.add(bParty);
}
return parties;
}
@Override
public String noticeTypes() {
return SignParamSource.super.noticeTypes();
}
private String getStringField(FormDataVo vo, String field) {
try {
FieldDataVo fieldData = vo.getFieldData(field);
return fieldData.getStringValue();
}catch (Exception e) {
return null;
}
}
public EsignConfigProvider getConfigProvider() {
return configProvider;
}
public void setConfigProvider(EsignConfigProvider configProvider) {
this.configProvider = configProvider;
}
public String getCallbackBaseUrl() {
return callbackBaseUrl == null ? "/seeyon/esigncallback.do?method=callback": "/seeyon" + callbackBaseUrl;
}
public void setCallbackBaseUrl(String callbackBaseUrl) {
this.callbackBaseUrl = callbackBaseUrl;
}
}

View File

@@ -0,0 +1,122 @@
package com.seeyon.apps.esign.po.param;
import com.seeyon.aicloud.common.JsonUtils;
import com.seeyon.apps.esign.po.signer.OrgInfo;
import com.seeyon.apps.esign.po.signer.PersonInfo;
import com.seeyon.apps.esign.po.signer.SignParty;
import com.seeyon.apps.esign.po.signer.SignerType;
import com.seeyon.apps.esign.service.SignParamSource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class JsonParamSource implements SignParamSource {
private Map<String,Object> oriParams;
private String callbackBaseUrl;
private List<SignParty> parties;
public JsonParamSource(){}
public JsonParamSource(String jsonStr){
this.oriParams = JsonUtils.parseObject(jsonStr,Map.class);
}
public JsonParamSource(Map<String,Object> params){
this.oriParams = params;
}
@Override
public String getContractTitle() {
return (String)oriParams.get("contractTitle");
}
@Override
public boolean isByFile() {
return (Boolean) oriParams.get("byFile");
}
@Override
public String getBizFormId() {
return (String)oriParams.get("formId");
}
@Override
public String getTableName() {
return (String)oriParams.get("tableName");
}
@Override
public String getSignFileRefId() {
return (String)oriParams.get("signFileRefId");
}
@Override
public String getSignedFileField() {
return (String)oriParams.get("signedFileField");
}
@Override
public String getSignStatusField() {
return (String)oriParams.get("signStatusField");
}
@Override
public Long getSignStatusEnumId() {
return oriParams.get("signStatusEnumId") == null ? null : Long.parseLong((String)oriParams.get("signStatusEnumId"));
}
@Override
public boolean autoSign() {
return false;
}
private String getCallbackBaseUrl() {
return callbackBaseUrl == null ? "/seeyon/esigncallback.do?method=callback": "/seeyon" + callbackBaseUrl;
}
@Override
public String getCallbackUrl() {
return getCallbackBaseUrl() + "&formId=" + getBizFormId() +
"&tablename=" + getTableName() +
"&updatefield=" + getSignedFileField() +
"&statusfield=" + getSignStatusField() + "_" + getSignStatusEnumId() +
"&bizType=FORM";
}
@Override
public List<SignParty> getSignerParties() {
String tempStr = (String)oriParams.get("signers");
List signers = JsonUtils.parseObject(tempStr, List.class);
List<SignParty> parties = new ArrayList<>();
for (Object signer : signers) {
Map<String,Object> signerMap = (Map<String,Object>) signer;
SignParty signParty = new SignParty();
SignerType signerType = SignerType.valueOf((String) signerMap.get("signerType"));
signParty.setSignerType(signerType);
signParty.setSignOrder((Integer) signerMap.get("signeOrder"));
signParty.setAutoSign(false);
signParty.setFreeSign(true);
signParty.setPartyId((String)signerMap.get("name"));
if(signerType == SignerType.PERSON) {
PersonInfo personInfo = new PersonInfo();
personInfo.setName((String)signerMap.get("name"));
personInfo.setPhone((String)signerMap.get("phone"));
signParty.setPersonInfo(personInfo);
}else {
OrgInfo orgInfo = new OrgInfo();
PersonInfo transactor = new PersonInfo();
orgInfo.setTransactor(transactor);
orgInfo.setOrgName((String)signerMap.get("orgName"));
orgInfo.setOrgCode((String)signerMap.get("orgCode"));
transactor.setName((String)signerMap.get("name"));
transactor.setPhone((String)signerMap.get("phone"));
signParty.setOrgInfo(orgInfo);
}
parties.add(signParty);
}
return parties;
}
public void setCallbackBaseUrl(String callbackBaseUrl) {
this.callbackBaseUrl = callbackBaseUrl;
}
}

View File

@@ -0,0 +1,13 @@
package com.seeyon.apps.esign.po.personal;
public class PsnInitiator {
private String psnId;
public String getPsnId() {
return psnId;
}
public void setPsnId(String psnId) {
this.psnId = psnId;
}
}

View File

@@ -0,0 +1,50 @@
package com.seeyon.apps.esign.po.seal;
public class SealInfoVo {
private String sealId; //印章ID
private String sealName; //印章名称
private String sealBizTypeDescription; //印章描述
private String statusDescription; //印章状态描述
private String sealImageDownloadUrl; //印章图片下载地址
public String getSealId() {
return sealId;
}
public void setSealId(String sealId) {
this.sealId = sealId;
}
public String getSealName() {
return sealName;
}
public void setSealName(String sealName) {
this.sealName = sealName;
}
public String getSealBizTypeDescription() {
return sealBizTypeDescription;
}
public void setSealBizTypeDescription(String sealBizTypeDescription) {
this.sealBizTypeDescription = sealBizTypeDescription;
}
public String getStatusDescription() {
return statusDescription;
}
public void setStatusDescription(String statusDescription) {
this.statusDescription = statusDescription;
}
public String getSealImageDownloadUrl() {
return sealImageDownloadUrl;
}
public void setSealImageDownloadUrl(String sealImageDownloadUrl) {
this.sealImageDownloadUrl = sealImageDownloadUrl;
}
}

View File

@@ -0,0 +1,163 @@
package com.seeyon.apps.esign.po.signer;
import com.seeyon.apps.esign.config.EsignConfigProvider;
import com.seeyon.apps.esign.constants.EsignConfigConstants;
import com.seeyon.apps.esign.po.signfield.NormalSignFieldConfig;
import com.seeyon.apps.esign.po.signfield.SignField;
import com.seeyon.apps.esign.po.signfield.SignFieldPosition;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class DefaultSignerBuilder implements SignerBuilder {
private EsignConfigProvider esignConfigProvider = EsignConfigProvider.getInstance();
@Override
public Signer build(List<String> fileIds,List<Object> keywordPos, SignParty party) {
if (party.getSignerType() == SignerType.PERSON) {
return buildPersonSigner(fileIds, keywordPos,party);
} else if (party.getSignerType() == SignerType.ORG) {
return buildOrgSigner(fileIds,keywordPos, party);
} else {
throw new IllegalArgumentException("不支持的签署方类型");
}
}
private Signer buildPersonSigner(List<String> fileIds,List<Object> keywordPos, SignParty party) {
PersonInfo psn = party.getPersonInfo();
if (psn == null) throw new IllegalStateException("个人签署方缺少 PersonInfo");
Signer signer = new Signer();
signer.setSignerType(0);
signer.setSignConfig(mapOf("signOrder", party.getSignOrder()));
if (!party.getAutoSign()) {
signer.setNoticeConfig(mapOf("noticeTypes", "1"));
signer.setPsnSignerInfo(mapOf(
"psnAccount", psn.getPhone(),
"psnInfo", mapOf(
"psnName", psn.getName(),
"psnIDCardNum", psn.getIdCardNo(),
"psnIDCardType", psn.getIdCardType()
)
));
}
signer.setSignFields(buildSignFields(fileIds, keywordPos, party));
return signer;
}
private Signer buildOrgSigner(List<String> fileIds, List<Object> keywordPos,SignParty party) {
OrgInfo org = party.getOrgInfo();
Signer signer = new Signer();
signer.setSignerType(1);
signer.setSignConfig(mapOf("signOrder", party.getSignOrder()));
if (!party.getAutoSign() && org != null) {
signer.setNoticeConfig(mapOf("noticeTypes", "1"));
signer.setOrgSignerInfo(mapOf(
"orgName", org.getOrgName(),
"orgInfo", mapOf(
"legalRepName", org.getLegalName(),
"legalRepIDCardNum", org.getLegalIdCardNo(),
"orgIDCardNum", org.getOrgCode(),
"orgIDCardType", "CRED_ORG_USCC"
),
"transactorInfo", mapOf(
"psnAccount", org.getTransactor().getPhone(),
"psnInfo", mapOf(
"psnName", org.getTransactor().getName(),
"psnIDCardNum", org.getTransactor().getIdCardNo()
)
)
));
}
signer.setSignFields(buildSignFields(fileIds,keywordPos,party));
return signer;
}
private List<SignFieldPosition> extractPosition(List<Object> positions, String keyword) {
List<SignFieldPosition> posList = new ArrayList<>();
for (Object obj : positions) {
Map<String, Object> position = (Map<String, Object>) obj;
if (Boolean.TRUE.equals(position.get("searchResult")) && keyword.equals(position.get("keyword"))) {
Object[] posArray = (Object[]) position.get("positions");
for (Object o : posArray) {
Map<String, Object> posMap = (Map<String, Object>)o;
Object[] coords = (Object[]) posMap.get("coordinates");
for (Object coord : coords) {
Map<String,Object> tempMap = (Map<String, Object>) coord;
SignFieldPosition sfp = new SignFieldPosition();
sfp.setPositionPage(posMap.get("pageNum") + "");
sfp.setPositionX(toFloat(tempMap.get("positionX")) + 150f);
sfp.setPositionY(toFloat(tempMap.get("positionY")));
posList.add(sfp);
}
}
return posList;
}
}
return new ArrayList<>();
}
private Float toFloat(Object val) {
return val instanceof Number ? ((Number) val).floatValue() : Float.parseFloat(val.toString());
}
private List<SignField> buildSignFields(List<String> fileIds,List<Object> keywordPos, SignParty party) {
List<SignField> signFields = new ArrayList<>();
for (String fileId : fileIds) {
if(!party.getFreeSign()) {
String searchKey = null;
SignFieldPosition qiFengposition = new SignFieldPosition();
qiFengposition.setAcrossPageMode("ALL");
if("甲方".equals(party.getPartyId())) {
searchKey = esignConfigProvider.getBizConfigByKey(EsignConfigConstants.aSignPositionKeyword);
qiFengposition.setPositionY(520f);
}else {
searchKey = esignConfigProvider.getBizConfigByKey(EsignConfigConstants.bSignPositionKeyword);
qiFengposition.setPositionY(720f);
}
List<SignFieldPosition> signFieldPositions = extractPosition(keywordPos, searchKey);
List<SignFieldPosition> lpSignFieldPositions = extractPosition(keywordPos, esignConfigProvider.getBizConfigByKey(EsignConfigConstants.lpSignPositionKeyword));
if(lpSignFieldPositions != null && lpSignFieldPositions.size() > 0) {
signFieldPositions.addAll(lpSignFieldPositions);
}
if(signFieldPositions.size() > 0) {
signFieldPositions.add(qiFengposition);
}
for (SignFieldPosition position : signFieldPositions) {
NormalSignFieldConfig fieldConfig = new NormalSignFieldConfig();
fieldConfig.setSignFieldPosition(position);
fieldConfig.setAutoSign(party.getAutoSign());
fieldConfig.setSignFieldStyle("ALL".equals(position.getAcrossPageMode()) ? 2 : 1);
SignField field = new SignField();
field.setSignFieldType(0);
field.setNormalSignFieldConfig(fieldConfig);
field.setFileId(fileId);
signFields.add(field);
}
}else {
NormalSignFieldConfig normalSignFieldConfig = new NormalSignFieldConfig();
normalSignFieldConfig.setAssignedSealId(party.getSealId());
normalSignFieldConfig.setFreeMode(true);
normalSignFieldConfig.setAutoSign(false);
normalSignFieldConfig.setAdaptableSignFieldSize(true);
SignField field = new SignField();
field.setSignFieldType(0);
field.setNormalSignFieldConfig(normalSignFieldConfig);
field.setFileId(fileId);
signFields.add(field);
}
}
return signFields;
}
private Map<String, Object> mapOf(Object... keyValues) {
if (keyValues.length % 2 != 0) throw new IllegalArgumentException("key-value 必须成对出现");
Map<String, Object> map = new HashMap<>();
for (int i = 0; i < keyValues.length; i += 2) {
map.put((String) keyValues[i], keyValues[i + 1]);
}
return map;
}
}

View File

@@ -0,0 +1,107 @@
package com.seeyon.apps.esign.po.signer;
import com.seeyon.apps.esign.config.EsignConfigProvider;
import com.seeyon.apps.esign.constants.EsignConfigConstants;
import com.seeyon.apps.esign.po.signfield.NormalSignFieldConfig;
import com.seeyon.apps.esign.po.signfield.SignField;
import com.seeyon.apps.esign.po.signfield.SignFieldPosition;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class JsonSignerBuilder implements SignerBuilder{
private EsignConfigProvider esignConfigProvider = EsignConfigProvider.getInstance();
@Override
public Signer build(List<String> fileIds, List<Object> keywordPos, SignParty party) {
if (party.getSignerType() == SignerType.PERSON) {
return buildPersonSigner(fileIds,party);
} else if (party.getSignerType() == SignerType.ORG) {
return buildOrgSigner(fileIds, party);
} else {
throw new IllegalArgumentException("不支持的签署方类型");
}
}
private Float toFloat(Object val) {
return val instanceof Number ? ((Number) val).floatValue() : Float.parseFloat(val.toString());
}
private List<SignField> buildSignFields(List<String> fileIds, SignParty party) {
List<SignField> signFields = new ArrayList<>();
for (String fileId : fileIds) {
NormalSignFieldConfig normalSignFieldConfig = new NormalSignFieldConfig();
normalSignFieldConfig.setAssignedSealId(party.getSealId());
normalSignFieldConfig.setFreeMode(true);
normalSignFieldConfig.setAutoSign(false);
normalSignFieldConfig.setAdaptableSignFieldSize(true);
SignField field = new SignField();
field.setSignFieldType(0);
field.setNormalSignFieldConfig(normalSignFieldConfig);
field.setFileId(fileId);
signFields.add(field);
}
return signFields;
}
private Map<String, Object> mapOf(Object... keyValues) {
if (keyValues.length % 2 != 0) throw new IllegalArgumentException("key-value 必须成对出现");
Map<String, Object> map = new HashMap<>();
for (int i = 0; i < keyValues.length; i += 2) {
map.put((String) keyValues[i], keyValues[i + 1]);
}
return map;
}
private Signer buildPersonSigner(List<String> fileIds, SignParty party) {
PersonInfo psn = party.getPersonInfo();
if (psn == null) throw new IllegalStateException("个人签署方缺少 PersonInfo");
Signer signer = new Signer();
signer.setSignerType(0);
signer.setSignConfig(mapOf("signOrder", party.getSignOrder()));
if (!party.getAutoSign()) {
signer.setNoticeConfig(mapOf("noticeTypes", "1"));
signer.setPsnSignerInfo(mapOf(
"psnAccount", psn.getPhone(),
"psnInfo", mapOf(
"psnName", psn.getName(),
"psnIDCardNum", psn.getIdCardNo(),
"psnIDCardType", psn.getIdCardType()
)
));
}
signer.setSignFields(buildSignFields(fileIds, party));
return signer;
}
private Signer buildOrgSigner(List<String> fileIds,SignParty party) {
OrgInfo org = party.getOrgInfo();
Signer signer = new Signer();
signer.setSignerType(1);
signer.setSignConfig(mapOf("signOrder", party.getSignOrder()));
if (!party.getAutoSign() && org != null) {
signer.setNoticeConfig(mapOf("noticeTypes", "1"));
signer.setOrgSignerInfo(mapOf(
"orgName", org.getOrgName(),
"orgInfo", mapOf(
"legalRepName", org.getLegalName(),
"legalRepIDCardNum", org.getLegalIdCardNo(),
"orgIDCardNum", org.getOrgCode(),
"orgIDCardType", "CRED_ORG_USCC"
),
"transactorInfo", mapOf(
"psnAccount", org.getTransactor().getPhone(),
"psnInfo", mapOf(
"psnName", org.getTransactor().getName(),
"psnIDCardNum", org.getTransactor().getIdCardNo()
)
)
));
}
signer.setSignFields(buildSignFields(fileIds,party));
return signer;
}
}

View File

@@ -0,0 +1,59 @@
package com.seeyon.apps.esign.po.signer;
public class OrgInfo {
/** 企业名称 */
private String orgName;
/** 统一社会信用代码 */
private String orgCode;
/** 法人姓名 */
private String legalName;
/** 法人身份证号 */
private String legalIdCardNo;
/** 经办人信息(企业签一定有) */
private PersonInfo transactor;
public String getOrgName() {
return orgName;
}
public void setOrgName(String orgName) {
this.orgName = orgName;
}
public String getOrgCode() {
return orgCode;
}
public void setOrgCode(String orgCode) {
this.orgCode = orgCode;
}
public String getLegalName() {
return legalName;
}
public void setLegalName(String legalName) {
this.legalName = legalName;
}
public String getLegalIdCardNo() {
return legalIdCardNo;
}
public void setLegalIdCardNo(String legalIdCardNo) {
this.legalIdCardNo = legalIdCardNo;
}
public PersonInfo getTransactor() {
return transactor;
}
public void setTransactor(PersonInfo transactor) {
this.transactor = transactor;
}
}

View File

@@ -0,0 +1,48 @@
package com.seeyon.apps.esign.po.signer;
public class PersonInfo {
/** 姓名 */
private String name;
/** 手机号(用于通知 / 登录) */
private String phone;
/** 身份证号(可选,企业经办人 / 强认证场景) */
private String idCardNo;
/** 身份证类型(可选) */
private String idCardType;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getIdCardNo() {
return idCardNo;
}
public void setIdCardNo(String idCardNo) {
this.idCardNo = idCardNo;
}
public String getIdCardType() {
return idCardType;
}
public void setIdCardType(String idCardType) {
this.idCardType = idCardType;
}
}

View File

@@ -0,0 +1,128 @@
package com.seeyon.apps.esign.po.signer;
import com.seeyon.apps.esign.po.signfield.SignFieldPosition;
import java.util.List;
public class SignParty {
/** 唯一标识(非必需,但强烈建议) */
private String partyId;
/** 签署顺序 */
private int signOrder;
/** 签署类型PERSON / ORG */
private SignerType signerType;
/** 是否自动签 */
private Boolean autoSign = false;
/** 印章ID企业签 */
private String sealId;
/** 通知手机号 */
private String notifyPhone;
/** 个人信息 */
private PersonInfo personInfo;
/** 企业信息 */
private OrgInfo orgInfo;
/** 签署位置 */
private List<SignFieldPosition> positions;
/** 签署关键字(可为空) */
private String signKeyword;
private Boolean freeSign = false;
public Boolean getFreeSign() {
return freeSign;
}
public void setFreeSign(Boolean freeSign) {
this.freeSign = freeSign;
}
public String getPartyId() {
return partyId;
}
public void setPartyId(String partyId) {
this.partyId = partyId;
}
public int getSignOrder() {
return signOrder;
}
public void setSignOrder(int signOrder) {
this.signOrder = signOrder;
}
public SignerType getSignerType() {
return signerType;
}
public void setSignerType(SignerType signerType) {
this.signerType = signerType;
}
public Boolean getAutoSign() {
return autoSign;
}
public void setAutoSign(Boolean autoSign) {
this.autoSign = autoSign;
}
public String getSealId() {
return sealId;
}
public void setSealId(String sealId) {
this.sealId = sealId;
}
public String getNotifyPhone() {
return notifyPhone;
}
public void setNotifyPhone(String notifyPhone) {
this.notifyPhone = notifyPhone;
}
public PersonInfo getPersonInfo() {
return personInfo;
}
public void setPersonInfo(PersonInfo personInfo) {
this.personInfo = personInfo;
}
public OrgInfo getOrgInfo() {
return orgInfo;
}
public void setOrgInfo(OrgInfo orgInfo) {
this.orgInfo = orgInfo;
}
public List<SignFieldPosition> getPositions() {
return positions;
}
public void setPositions(List<SignFieldPosition> positions) {
this.positions = positions;
}
public String getSignKeyword() {
return signKeyword;
}
public void setSignKeyword(String signKeyword) {
this.signKeyword = signKeyword;
}
}

View File

@@ -0,0 +1,65 @@
package com.seeyon.apps.esign.po.signer;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.seeyon.apps.esign.po.signfield.SignField;
import java.util.List;
import java.util.Map;
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class Signer {
private int signerType;
private Map<String,Object> signConfig;
private Map<String,Object> noticeConfig;
private Map<String,Object> orgSignerInfo;
private Map<String,Object> psnSignerInfo;
private List<SignField> signFields;
public int getSignerType() {
return signerType;
}
public void setSignerType(int signerType) {
this.signerType = signerType;
}
public Map<String, Object> getNoticeConfig() {
return noticeConfig;
}
public void setNoticeConfig(Map<String, Object> noticeConfig) {
this.noticeConfig = noticeConfig;
}
public Map<String, Object> getOrgSignerInfo() {
return orgSignerInfo;
}
public void setOrgSignerInfo(Map<String, Object> orgSignerInfo) {
this.orgSignerInfo = orgSignerInfo;
}
public Map<String, Object> getPsnSignerInfo() {
return psnSignerInfo;
}
public void setPsnSignerInfo(Map<String, Object> psnSignerInfo) {
this.psnSignerInfo = psnSignerInfo;
}
public List<SignField> getSignFields() {
return signFields;
}
public void setSignFields(List<SignField> signFields) {
this.signFields = signFields;
}
public Map<String, Object> getSignConfig() {
return signConfig;
}
public void setSignConfig(Map<String, Object> signConfig) {
this.signConfig = signConfig;
}
}

View File

@@ -0,0 +1,26 @@
package com.seeyon.apps.esign.po.signer;
import java.util.ArrayList;
import java.util.List;
public interface SignerBuilder {
/**
* 根据签署方信息构建 Signer
*/
Signer build(List<String> fileIds, List<Object> keywordPos,SignParty party);
/**
* 批量构建(默认能力)
*/
default List<Signer> buildAll(List<String> fileIds,List<Object> keywordPos,List<SignParty> parties) {
List<Signer> signers = new ArrayList<>();
for (SignParty party : parties) {
Signer signer = build(fileIds,keywordPos, party);
if (signer != null) {
signers.add(signer);
}
}
return signers;
}
}

View File

@@ -0,0 +1,5 @@
package com.seeyon.apps.esign.po.signer;
public enum SignerType {
PERSON, ORG
}

View File

@@ -0,0 +1,58 @@
package com.seeyon.apps.esign.po.signfield;
public class NormalSignFieldConfig {
private Boolean autoSign;
private Integer signFieldStyle;
private SignFieldPosition signFieldPosition;
private String assignedSealId; //指定签章id
private Boolean freeMode = false;
private Boolean adaptableSignFieldSize;//是否自适应签章大小
public Boolean getAutoSign() {
return autoSign;
}
public void setAutoSign(Boolean autoSign) {
this.autoSign = autoSign;
}
public Integer getSignFieldStyle() {
return signFieldStyle;
}
public void setSignFieldStyle(Integer signFieldStyle) {
this.signFieldStyle = signFieldStyle;
}
public SignFieldPosition getSignFieldPosition() {
return signFieldPosition;
}
public void setSignFieldPosition(SignFieldPosition signFieldPosition) {
this.signFieldPosition = signFieldPosition;
}
public String getAssignedSealId() {
return assignedSealId;
}
public void setAssignedSealId(String assignedSealId) {
this.assignedSealId = assignedSealId;
}
public Boolean getFreeMode() {
return freeMode;
}
public void setFreeMode(Boolean freeMode) {
this.freeMode = freeMode;
}
public Boolean getAdaptableSignFieldSize() {
return adaptableSignFieldSize;
}
public void setAdaptableSignFieldSize(Boolean adaptableSignFieldSize) {
this.adaptableSignFieldSize = adaptableSignFieldSize;
}
}

View File

@@ -0,0 +1,32 @@
package com.seeyon.apps.esign.po.signfield;
public class RemarkSignFieldConfig {
private boolean freeMode = false;
private int inputType = 1;
private String remarkContent = "";
public boolean isFreeMode() {
return freeMode;
}
public void setFreeMode(boolean freeMode) {
this.freeMode = freeMode;
}
public int getInputType() {
return inputType;
}
public void setInputType(int inputType) {
this.inputType = inputType;
}
public String getRemarkContent() {
return remarkContent;
}
public void setRemarkContent(String remarkContent) {
this.remarkContent = remarkContent;
}
}

View File

@@ -0,0 +1,42 @@
package com.seeyon.apps.esign.po.signfield;
public class SignField {
private String fileId;
private Integer signFieldType;
private NormalSignFieldConfig normalSignFieldConfig;
private RemarkSignFieldConfig remarkSignFieldConfig;
public String getFileId() {
return fileId;
}
public void setFileId(String fileId) {
this.fileId = fileId;
}
public Integer getSignFieldType() {
return signFieldType;
}
public void setSignFieldType(Integer signFieldType) {
this.signFieldType = signFieldType;
}
public NormalSignFieldConfig getNormalSignFieldConfig() {
return normalSignFieldConfig;
}
public void setNormalSignFieldConfig(NormalSignFieldConfig normalSignFieldConfig) {
this.normalSignFieldConfig = normalSignFieldConfig;
}
public RemarkSignFieldConfig getRemarkSignFieldConfig() {
return remarkSignFieldConfig;
}
public void setRemarkSignFieldConfig(RemarkSignFieldConfig remarkSignFieldConfig) {
this.remarkSignFieldConfig = remarkSignFieldConfig;
}
}

View File

@@ -0,0 +1,41 @@
package com.seeyon.apps.esign.po.signfield;
public class SignFieldPosition {
private String acrossPageMode;
private String positionPage;
private Float positionX;
private Float positionY;
public String getAcrossPageMode() {
return acrossPageMode;
}
public void setAcrossPageMode(String acrossPageMode) {
this.acrossPageMode = acrossPageMode;
}
public String getPositionPage() {
return positionPage;
}
public void setPositionPage(String positionPage) {
this.positionPage = positionPage;
}
public Float getPositionX() {
return positionX;
}
public void setPositionX(Float positionX) {
this.positionX = positionX;
}
public Float getPositionY() {
return positionY;
}
public void setPositionY(Float positionY) {
this.positionY = positionY;
}
}

View File

@@ -0,0 +1,49 @@
package com.seeyon.apps.esign.po.upload;
public class EsignFileUploadParams {
private String contentMd5;
private String contentType;
private String fileName;
private Long fileSize;
private Boolean convertToPDF = false;
public String getContentMd5() {
return contentMd5;
}
public void setContentMd5(String contentMd5) {
this.contentMd5 = contentMd5;
}
public String getContentType() {
return contentType;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public Long getFileSize() {
return fileSize;
}
public void setFileSize(Long fileSize) {
this.fileSize = fileSize;
}
public Boolean getConvertToPDF() {
return convertToPDF;
}
public void setConvertToPDF(Boolean convertToPDF) {
this.convertToPDF = convertToPDF;
}
}

View File

@@ -0,0 +1,23 @@
package com.seeyon.apps.esign.po.upload;
public class GetUploadUrlResp {
private String fileId;
private String fileUploadUrl;
public String getFileId() {
return fileId;
}
public void setFileId(String fileId) {
this.fileId = fileId;
}
public String getFileUploadUrl() {
return fileUploadUrl;
}
public void setFileUploadUrl(String fileUploadUrl) {
this.fileUploadUrl = fileUploadUrl;
}
}

View File

@@ -0,0 +1,31 @@
package com.seeyon.apps.esign.service;
import com.seeyon.ctp.common.AppContext;
import java.util.List;
import java.util.Map;
public class ContractCreateService {
private EsignByTemplateService templateService = (EsignByTemplateService) AppContext.getBean("esignByTemplateService");
private List<SignParamBuildFactory> signParamBuildFactories;
public String startSign(SignParamSource source) throws Exception {
for (SignParamBuildFactory factory : signParamBuildFactories) {
if(factory.support(source)){
Map<String, Object> buildParam = factory.buildParam(source);
if (buildParam == null) throw new RuntimeException("签署参数构建失败");
return templateService.createBySignTemplate(buildParam);
}
}
return null;
}
public List<SignParamBuildFactory> getSignParamBuildFactories() {
return signParamBuildFactories;
}
public void setSignParamBuildFactories(List<SignParamBuildFactory> signParamBuildFactories) {
this.signParamBuildFactories = signParamBuildFactories;
}
}

View File

@@ -0,0 +1,33 @@
package com.seeyon.apps.esign.service;
import com.seeyon.aicloud.common.JsonUtils;
import com.seeyon.apps.esign.config.EsignConfigProvider;
import com.seeyon.apps.esign.constants.EsignApiUrl;
import com.seeyon.apps.esign.constants.EsignConfigConstants;
import com.seeyon.apps.esign.po.esignapi.EsignApiHeader;
import com.seeyon.apps.esign.po.esignapi.EsignBaseResp;
import com.seeyon.apps.esign.utils.HttpClient;
import com.seeyon.ctp.common.AppContext;
import java.util.Map;
public class EsignAuthService {
private EsignConfigProvider configProvider = (EsignConfigProvider) AppContext.getBean("esignConfigProvider");
public void personAuth(Map<String,Object> authParams) throws Exception {
EsignApiHeader esignApiHeader = EsignApiHeader.build();
String jsonBody = JsonUtils.toJSONString(authParams);
esignApiHeader.appId(configProvider.getBizConfigByKey(EsignConfigConstants.APP_ID))
.httpMethod("POST")
.heads("")
.pathAndParameters(EsignApiUrl.PERSON_AUTH_URL)
.contentMD5(jsonBody)
.signature(configProvider.getBizConfigByKey(EsignConfigConstants.APP_SECRET));
String url = configProvider.getBizConfigByKey(EsignConfigConstants.ESIGN_HOST) + EsignApiUrl.PERSON_AUTH_URL;
String respStr = HttpClient.httpPostRaw(url, jsonBody, esignApiHeader.convert2Headers(), "UTF-8");
EsignBaseResp esignBaseResp = JsonUtils.parseObject(respStr, EsignBaseResp.class);
Map<String,Object> dataMap = (Map<String, Object>) esignBaseResp.getData();
}
}

View File

@@ -0,0 +1,54 @@
package com.seeyon.apps.esign.service;
import com.seeyon.aicloud.common.JsonUtils;
import com.seeyon.apps.esign.config.EsignConfigProvider;
import com.seeyon.apps.esign.constants.EsignApiUrl;
import com.seeyon.apps.esign.constants.EsignConfigConstants;
import com.seeyon.apps.esign.po.esignapi.EsignApiHeader;
import com.seeyon.apps.esign.po.esignapi.EsignBaseResp;
import com.seeyon.apps.esign.utils.HttpClient;
import com.seeyon.apps.esign.utils.JsonCleaner;
import com.seeyon.ctp.common.AppContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.Map;
public class EsignByTemplateService {
private EsignConfigProvider configProvider = EsignConfigProvider.getInstance();
private TokenCacheManager tokenCacheManager = (TokenCacheManager) AppContext.getBean("tokenCacheManager");
private static final Log log = LogFactory.getLog(EsignByTemplateService.class);
public void signByTemplate(Map<String,Object> params) {
}
public void startSignFlow(String flowId) throws Exception {
String url = configProvider.getBizConfigByKey(EsignConfigConstants.ESIGN_HOST) + EsignApiUrl.SIGN_START_URL;
url.replace("{signFlowId}", flowId);
String respStr = HttpClient.httpPostRaw(url, "", null, null);
EsignBaseResp esignBaseResp = JsonUtils.parseObject(respStr, EsignBaseResp.class);
if (esignBaseResp.getCode() != 0) {
throw new Exception("签署发起失败");
}
}
public String createBySignTemplate(Map<String,Object> params) throws Exception {
EsignApiHeader esignApiHeader = EsignApiHeader.build();
String jsonBody = JsonCleaner.removeEmptyObjects(JsonUtils.toJSONString(params));
esignApiHeader.token(tokenCacheManager.getToken()).appId(configProvider.getBizConfigByKey(EsignConfigConstants.APP_ID));
String url = configProvider.getBizConfigByKey(EsignConfigConstants.ESIGN_HOST) + EsignApiUrl.SIGN_BY_FILE_URL;
log.info("合同发起入参: " + jsonBody);
String respStr = HttpClient.httpPostRaw(url, jsonBody, esignApiHeader.convert2Headers(), "UTF-8");
EsignBaseResp esignBaseResp = JsonUtils.parseObject(respStr, EsignBaseResp.class);
Map<String,Object> dataMap = (Map<String, Object>) esignBaseResp.getData();
if(!"0".equals(esignBaseResp.getCode() + "")) {
throw new RuntimeException("签署发起失败," + esignBaseResp.getMessage());
}
String flowId = (String) dataMap.get("signFlowId");
return flowId;
}
}

View File

@@ -0,0 +1,7 @@
package com.seeyon.apps.esign.service;
public interface EsignCallbackBizService {
public void handleSuccessSignCallbackBiz(String tablename,String updatefield,String statusField,String formId,Object[] fileInfos) throws Exception;
public void handleFailSignCallbackBiz(String tableName,String statusField,String formId,String failMsg) throws Exception;
}

View File

@@ -0,0 +1,89 @@
package com.seeyon.apps.esign.service;
import com.alibaba.fastjson.JSONObject;
import com.seeyon.apps.esign.config.EsignConfigProvider;
import com.seeyon.apps.esign.constants.EsignConfigConstants;
import com.seeyon.apps.esign.utils.FileUtil;
import com.seeyon.apps.esign.utils.ProtUtil;
import com.seeyon.ctp.common.AppContext;
import com.seeyon.ctp.util.JDBCAgent;
import com.seeyon.utils.form.EnumMapUtils;
import com.seeyon.utils.form.FormTableExecutor;
import com.seeyon.utils.form.FormUpdateField;
import com.seeyon.utils.form.FormWhereCondition;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class EsignCallbackFlowBizService implements EsignCallbackBizService{
private static final Log log = LogFactory.getLog(EsignCallbackFlowBizService.class);
private ProtUtil protUtil = (ProtUtil) AppContext.getBean("protUtil");
private EsignConfigProvider configProvider = EsignConfigProvider.getInstance();
public void handleSuccessSignCallbackBiz(String tablename,String updatefield,String statusField,String formId,Object[] fileInfos) throws Exception {
String[] strings = formId.split("_");
String oaFlowId = strings[0];
String tempFormId = strings[1];
String[] statusParams = statusField.split("_");
String status = statusParams[0];
String enumId = statusParams[1];
String enumItemId = EnumMapUtils.getEnumItemValueByEnumId("已签署",Long.parseLong(enumId));
//下载文件到本地
List<FormWhereCondition> conditions = new ArrayList<>();
String refId = FileUtil.uploadContractToOA(fileInfos, getModuleId(tempFormId),
configProvider.getBizConfigByKey(EsignConfigConstants.FORMEDITLOGINNAME),
configProvider.getBizConfigByKey(EsignConfigConstants.updateAccountName));
List<FormUpdateField> updateFields = new ArrayList<>();
updateFields.add(FormUpdateField.build().fieldName(updatefield).value(refId));
updateFields.add(FormUpdateField.build().fieldName(status).value(enumItemId));
conditions.add(FormWhereCondition.build().value(tempFormId).fieldName("ID"));
JSONObject params = new JSONObject();
params.put("message", "签署完成!!!");
params.put("returnCode", 1);
protUtil.sendPostNotification(params.toString(), configProvider.getBizConfigByKey(EsignConfigConstants.nodeTokenUrl), oaFlowId);
FormTableExecutor.update(tablename,updateFields,conditions);
}
public void handleFailSignCallbackBiz(String tableName,String statusField,String formId,String failMsg) throws Exception {
String[] strings = formId.split("_");
String oaFlowId = strings[0];
String tempFormId = strings[1];
String[] statusParams = statusField.split("_");
String status = statusParams[0];
String enumId = statusParams[1];
String enumItemId = EnumMapUtils.getEnumItemValueByEnumId("签署失败",Long.parseLong(enumId));
List<FormWhereCondition> conditions = new ArrayList<>();
List<FormUpdateField> updateFields = new ArrayList<>();
updateFields.add(FormUpdateField.build().fieldName(status).value(enumItemId));
conditions.add(FormWhereCondition.build().value(tempFormId).fieldName("ID"));
JSONObject params = new JSONObject();
params.put("message", "签署失败: " + failMsg);
params.put("returnCode", 2);
protUtil.sendPostNotification(params.toString(), configProvider.getBizConfigByKey(EsignConfigConstants.nodeTokenUrl), oaFlowId);
FormTableExecutor.update(tableName,updateFields,conditions);
}
private String getModuleId(String formId) {
JDBCAgent jdbcAgent = new JDBCAgent();
try {
String sql = "SELECT MODULE_ID FROM ctp_content_all where CONTENT_DATA_ID = ?";
List<Object> params = new ArrayList<>();
params.add(formId);
jdbcAgent.execute(sql,params);
List list = jdbcAgent.resultSetToList();
if(list == null || !(list.size() > 0)) {
throw new RuntimeException("MODULE_ID获取失败");
}
Map<String,Object> map = (Map<String, Object>) list.get(0);
return map.get("module_id") +"";
}catch (Exception e) {
log.error(e.getMessage(),e);
}
return null;
}
}

View File

@@ -0,0 +1,133 @@
package com.seeyon.apps.esign.service;
import com.seeyon.aicloud.common.JsonUtils;
import com.seeyon.apps.esign.config.EsignConfigProvider;
import com.seeyon.apps.esign.constants.EsignApiUrl;
import com.seeyon.apps.esign.constants.EsignConfigConstants;
import com.seeyon.apps.esign.po.esignapi.EsignApiHeader;
import com.seeyon.apps.esign.po.esignapi.EsignBaseResp;
import com.seeyon.apps.esign.po.file.SignFile;
import com.seeyon.apps.esign.po.file.TemplateComponent;
import com.seeyon.apps.esign.utils.HttpClient;
import com.seeyon.ctp.common.AppContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class EsignFileTemplateService {
private static final String ORI_TEMPLATE = "原始合同模板文件";
private static final Log log = LogFactory.getLog(EsignFileTemplateService.class);
private EsignConfigProvider configProvider = EsignConfigProvider.getInstance();
private TokenCacheManager tokenCacheManager = (TokenCacheManager) AppContext.getBean("tokenCacheManager");
private EsignUploadFileService uploadFileService = (EsignUploadFileService) AppContext.getBean("esignUploadFileService");
private String orgId;
private void fillOrgId() {
EsignApiHeader esignApiHeader = EsignApiHeader.build();
try {
esignApiHeader.token(tokenCacheManager.getToken()).appId(configProvider.getBizConfigByKey(EsignConfigConstants.APP_ID));
} catch (Exception e) {
e.printStackTrace();
}
//获取orgId
String queryStr = EsignApiUrl.QUERY_ORGINFO + "?orgName=" + configProvider.getBizConfigByKey(EsignConfigConstants.UNITNAME);
String reqUrl = configProvider.getBizConfigByKey(EsignConfigConstants.ESIGN_HOST) + queryStr;
String orgInfoRespStr = HttpClient.httpGet(reqUrl, esignApiHeader.convert2Headers(), "UTF-8");
EsignBaseResp orgInfoResp = JsonUtils.parseObject(orgInfoRespStr, EsignBaseResp.class);
Map<String, Object> orgData = (Map<String, Object>) orgInfoResp.getData();
orgId = (String) orgData.get("orgId");
}
//填充模板
public SignFile fillTemplate(String templateId, String fileName, Map<String,Object> params) {
//请求示例
Map<String,Object> reqParams = new HashMap<>();
reqParams.put("docTemplateId",templateId);
reqParams.put("fileName",fileName);
List<TemplateComponent> components = new ArrayList<>();
Set<String> keySets = params.keySet();
for (String key : keySets) {
TemplateComponent component = new TemplateComponent();
component.setComponentKey(key);
component.setComponentValue((String) params.get(key));
components.add(component);
}
reqParams.put("components",components);
String url = "";
String resp = HttpClient.httpPostRaw(url, JsonUtils.toJSONString(reqParams), null, null);
EsignBaseResp esignBaseResp = JsonUtils.parseObject(resp, EsignBaseResp.class);
if(esignBaseResp.getCode() != 0) {}
Map<String,Object> dataMap = (Map<String, Object>) esignBaseResp.getData();
SignFile signFile = new SignFile();
signFile.setFileId((String) dataMap.get("fileId"));
signFile.setFileName(fileName);
return signFile;
}
//获取模板详细信息
public Map<String,Object> getTemplateDetail(String signTemplateId,String orgId,Boolean queryComponents) {
String url = configProvider.getBizConfigByKey(EsignConfigConstants.ESIGN_HOST) + "?" + "signTemplateId=" + signTemplateId + "&orgId=" + orgId + (queryComponents != null ? "&queryComponents=" + queryComponents : "");
String resp = HttpClient.httpGet(url, null, "UTF-8");
EsignBaseResp esignBaseResp = JsonUtils.parseObject(resp, EsignBaseResp.class);
Map<String,Object> data = (Map<String, Object>) esignBaseResp.getData();
return data;
}
//获取模板详细信息
public Map<String,Object> getTemplateDetail(String signTemplateId,String orgId) {
String url = configProvider.getBizConfigByKey(EsignConfigConstants.ESIGN_HOST) + EsignApiUrl.QUERY_TEMPLATE_DETAIL_URL + "?" +"orgId=" + orgId + "&signTemplateId=" + signTemplateId;
EsignApiHeader apiHeader = EsignApiHeader.build().token(tokenCacheManager.getToken()).appId(configProvider.getBizConfigByKey(EsignConfigConstants.APP_ID));
String resp = HttpClient.httpGet(url, apiHeader.convert2Headers(), "UTF-8");
EsignBaseResp esignBaseResp = JsonUtils.parseObject(resp, EsignBaseResp.class);
Map<String,Object> data = (Map<String, Object>) esignBaseResp.getData();
return data;
}
public Map<String,Object> queryTemplates(Integer pageNo) throws Exception {
EsignApiHeader esignApiHeader = EsignApiHeader.build().appId(configProvider.getBizConfigByKey(EsignConfigConstants.APP_ID));
String queryStr = EsignApiUrl.QUERY_TEMPLATES_URL + "?" + "orgId=" + obtainOrgId() + "&pageNum=" + pageNo + "&pageSize=" + 20 + "&status=" + 1;
esignApiHeader.token(tokenCacheManager.getToken());
String url = configProvider.getBizConfigByKey(EsignConfigConstants.ESIGN_HOST) + queryStr;
String templateListRespStr = HttpClient.httpGet(url, esignApiHeader.convert2Headers(), "UTF-8");
EsignBaseResp templateListResp = JsonUtils.parseObject(templateListRespStr, EsignBaseResp.class);
Map<String,Object> listData = (Map<String,Object>)templateListResp.getData();
Integer total = (Integer) listData.get("total");
Object[] templateArray = (Object[]) listData.get("signTemplates");
Map<String,Object> pageMap = new HashMap<>();
pageMap.put("total",total);
pageMap.put("templateList",templateArray);
return pageMap;
}
public String getCompareDetailUrl(String templateRefId,String contractRefId) throws Exception {
String templateFileId = uploadFileService.uploadFileToEsign(templateRefId).get(0);
String contractFileId = uploadFileService.uploadFileToEsign(contractRefId).get(0);
String url = configProvider.getBizConfigByKey(EsignConfigConstants.ESIGN_HOST) + EsignApiUrl.CONTRACT_COMPARE_GETURL;
Map<String,String> params = new HashMap<>();
params.put("standardFileId",templateFileId);
params.put("comparativeFileId",contractFileId);
String jsonString = JsonUtils.toJSONString(params);
EsignApiHeader esignApiHeader = EsignApiHeader.build().appId(configProvider.getBizConfigByKey(EsignConfigConstants.APP_ID));
esignApiHeader.token(tokenCacheManager.getToken());
String respStr = HttpClient.httpPostRaw(url, jsonString, esignApiHeader.convert2Headers(), null);
EsignBaseResp esignBaseResp = JsonUtils.parseObject(respStr, EsignBaseResp.class);
log.info("调用获取合同比对链接接口返回值: " + JsonUtils.toJSONString(esignBaseResp));
Map<String,String> data = (Map<String, String>) esignBaseResp.getData();
String contractCompareUrl = data.get("contractCompareUrl");
return contractCompareUrl;
}
private String obtainOrgId() {
if(orgId == null) {
fillOrgId();
}
return orgId;
}
}

View File

@@ -0,0 +1,32 @@
package com.seeyon.apps.esign.service;
import com.seeyon.aicloud.common.JsonUtils;
import com.seeyon.apps.esign.config.EsignConfigProvider;
import com.seeyon.apps.esign.constants.EsignApiUrl;
import com.seeyon.apps.esign.constants.EsignConfigConstants;
import com.seeyon.apps.esign.po.esignapi.EsignApiHeader;
import com.seeyon.apps.esign.po.esignapi.EsignBaseResp;
import com.seeyon.ctp.common.AppContext;
import com.seeyon.utils.http.HttpClient;
import java.util.Map;
public class EsignFlowQueryService {
private TokenCacheManager tokenCacheManager = (TokenCacheManager) AppContext.getBean("tokenCacheManager");
private EsignConfigProvider esignConfigProvider = EsignConfigProvider.getInstance();
public Integer queryFlow(String eFlowId){
EsignApiHeader esignApiHeader = EsignApiHeader.build();
esignApiHeader.token(tokenCacheManager.getToken()).appId(esignConfigProvider.getBizConfigByKey(EsignConfigConstants.APP_ID));
String url = esignConfigProvider.getBizConfigByKey(EsignConfigConstants.ESIGN_HOST) + EsignApiUrl.SIGN_FLOW_QUERY.replace("{signFlowId}",eFlowId);
String respStr = HttpClient.httpGet(url, esignApiHeader.convert2Headers(), "UTF-8");
EsignBaseResp esignBaseResp = JsonUtils.parseObject(respStr, EsignBaseResp.class);
Map<String,Object> dataMap = (Map<String, Object>) esignBaseResp.getData();
if(!"0".equals(esignBaseResp.getCode() + "")) {
throw new RuntimeException("合同信息查询失败," + esignBaseResp.getMessage());
}
Integer flowStatus = (Integer) dataMap.get("signFlowStatus");
return flowStatus; //0 - 草稿 1 - 签署中 2 - 完成 3 - 撤销 5 - 过期签署截至日期到期后触发7 - 拒签
}
}

View File

@@ -0,0 +1,187 @@
package com.seeyon.apps.esign.service;
import com.seeyon.aicloud.common.JsonUtils;
import com.seeyon.apps.esign.config.EsignConfigProvider;
import com.seeyon.apps.esign.constants.EsignApiUrl;
import com.seeyon.apps.esign.constants.EsignConfigConstants;
import com.seeyon.apps.esign.po.esignapi.EsignApiHeader;
import com.seeyon.apps.esign.po.esignapi.EsignBaseResp;
import com.seeyon.apps.esign.po.upload.EsignFileUploadParams;
import com.seeyon.apps.esign.po.esignapi.EsignHttpResponse;
import com.seeyon.apps.esign.po.upload.GetUploadUrlResp;
import com.seeyon.apps.esign.utils.EsignHttpHelper;
import com.seeyon.apps.esign.utils.EsignRequestType;
import com.seeyon.apps.esign.utils.FileUtil;
import com.seeyon.apps.esign.utils.HttpClient;
import com.seeyon.ctp.common.AppContext;
import org.apache.commons.codec.binary.Base64;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class EsignUploadFileService {
private EsignConfigProvider configProvider = EsignConfigProvider.getInstance();
protected TokenCacheManager tokenCacheManager = (TokenCacheManager) AppContext.getBean("tokenCacheManager");
public Object[] getDownloadFileInfo(String flowId) throws Exception {
String reqPath = EsignApiUrl.CONTRACT_DOWNLOAD_URL.replace("{signFlowId}", flowId);
String getDownloadUrl = configProvider.getBizConfigByKey(EsignConfigConstants.ESIGN_HOST) + reqPath;
EsignApiHeader esignApiHeader = EsignApiHeader.build().appId(configProvider.getBizConfigByKey(EsignConfigConstants.APP_ID)).token(tokenCacheManager.getToken());
String respStr = HttpClient.httpGet(getDownloadUrl, esignApiHeader.convert2Headers(), null);
EsignBaseResp esignBaseResp = JsonUtils.parseObject(respStr, EsignBaseResp.class);
if(esignBaseResp.getCode() != 0 || esignBaseResp.getData() == null){
throw new RuntimeException("下载合同文件失败");
}
Map<String,Object> data = (Map<String, Object>) esignBaseResp.getData();
Object[] files = (Object[]) data.get("files");
if(files.length <= 0) {
throw new RuntimeException("下载合同文件失败");
}
return files;
}
public GetUploadUrlResp getUploadFileUrl(String fileName,String fileMd5,Long fileSize,boolean convert2Pdf) throws Exception {
String url = configProvider.getBizConfigByKey(EsignConfigConstants.ESIGN_HOST) + EsignApiUrl.GET_UPLOAD_FILE_URL;
GetUploadUrlResp resp = new GetUploadUrlResp();
EsignApiHeader esignApiHeader = EsignApiHeader.build().appId(configProvider.getBizConfigByKey(EsignConfigConstants.APP_ID));
esignApiHeader.token(tokenCacheManager.getToken());
EsignFileUploadParams params = new EsignFileUploadParams();
params.setFileName(fileName);
params.setContentMd5(fileMd5);
params.setFileSize(fileSize);
params.setConvertToPDF(convert2Pdf);
params.setContentType("application/octet-stream");
String respStr = HttpClient.httpPostRaw(url, JsonUtils.toJSONString(params),esignApiHeader.convert2Headers(), null);
EsignBaseResp esignBaseResp = JsonUtils.parseObject(respStr, EsignBaseResp.class);
Object data = esignBaseResp.getData();
if (data != null) {
Map<String,Object> map = (Map<String, Object>) data;
resp.setFileUploadUrl((String) map.get("fileUploadUrl"));
resp.setFileId((String) map.get("fileId"));
return resp;
}else {
throw new RuntimeException("获取合同上传地址失败: " + esignBaseResp.getMessage());
}
}
public List<Object> getSignPosition(String fileId,List<String> keywords) {
try {
String reqPath = EsignApiUrl.SIGN_POSITION_URL.replace("{fileId}", fileId);
String url = configProvider.getBizConfigByKey(EsignConfigConstants.ESIGN_HOST) + reqPath;
EsignApiHeader esignApiHeader = EsignApiHeader.build().appId(configProvider.getBizConfigByKey(EsignConfigConstants.APP_ID));
Map<String,Object> params = new HashMap<>();
params.put("keywords",keywords);
esignApiHeader.token(tokenCacheManager.getToken());
String respStr = HttpClient.httpPostRaw(url,JsonUtils.toJSONString(params),esignApiHeader.convert2Headers(),null);
Map map = JsonUtils.parseObject(respStr, Map.class);
Map<String,Object> data = (Map<String,Object>) map.get("data");
Object[] keywordPositions = (Object[]) data.get("keywordPositions");
List<Object> resList = new ArrayList<>();
for (Object position : keywordPositions) {
resList.add(position);
}
return resList;
}catch (Exception e){
}
return new ArrayList<>();
}
public List<String> uploadFileToEsign(String refId) throws Exception {
String tempDir = System.getProperty("java.io.tmpdir");
List<String> fileIds = new ArrayList<>();
File file = null;
FileUtil fileUtil = new FileUtil();
try {
List<String> paths = fileUtil.fieldFileDownload(Long.parseLong(refId), tempDir + File.separator + "oafile" + File.separator);
for (String path : paths) {
file = new File(path);
String contentMD5 = EsignUploadFileService.getFileContentMD5(path);
GetUploadUrlResp uploadResp = getUploadFileUrl(file.getName(), contentMD5, file.length(),false);
uploadFile(uploadResp.getFileUploadUrl(), contentMD5, file.getName(), path);
fileIds.add(uploadResp.getFileId());
}
return fileIds;
}finally {
if(file != null) {
file.delete();
}
}
}
public static String getFileContentMD5(String filePath) throws Exception {
// 获取文件MD5的二进制数组128位
byte[] bytes = getFileMD5Bytes128(filePath);
// 对文件MD5的二进制数组进行base64编码
return new String(Base64.encodeBase64String(bytes));
}
/***
* 获取文件MD5-二进制数组128位
*
* @return
* @throws IOException
*/
public static byte[] getFileMD5Bytes128(String filePath) throws Exception {
byte[] md5Bytes = null;
File file = new File(filePath);
try (FileInputStream fis = new FileInputStream(file)) {
MessageDigest md5 = MessageDigest.getInstance("MD5");
byte[] buffer = new byte[1024];
int length = -1;
while ((length = fis.read(buffer, 0, 1024)) != -1) {
md5.update(buffer, 0, length);
}
md5Bytes = md5.digest();
}
return md5Bytes;
}
public String uploadFile(String uploadUrl,String contentMD5,String fileName,String filePath) throws Exception {
// EsignApiHeader esignApiHeader = EsignApiHeader.build();
// esignApiHeader.setContentType("application/octet-stream");
// esignApiHeader.setContentMd5(contentMD5);
EsignHttpResponse esignHttpResponse = EsignHttpHelper.doUploadHttp(uploadUrl, EsignRequestType.PUT, getBytes(filePath), contentMD5, "application/octet-stream", false);
// return HttpClient.uploadBinaryFile(uploadUrl,esignApiHeader.convert2Headers(),new FileInputStream(file),fileName);
return esignHttpResponse.getBody();
}
public static byte[] getBytes(String filePath) throws Exception {
File file = new File(filePath);
FileInputStream fis = null;
byte[] buffer = null;
try {
fis = new FileInputStream(file);
buffer = new byte[(int) file.length()];
fis.read(buffer);
} catch (Exception e) {
Exception ex = new Exception("获取文件字节流失败", e);
ex.initCause(e);
throw ex;
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
Exception ex = new Exception("关闭文件字节流失败", e);
ex.initCause(e);
throw ex;
}
}
}
return buffer;
}
}

View File

@@ -0,0 +1,102 @@
package com.seeyon.apps.esign.service;
import com.seeyon.apps.esign.config.EsignConfigProvider;
import com.seeyon.apps.esign.constants.EsignConfigConstants;
import com.seeyon.apps.esign.po.param.FlowParamSource;
import com.seeyon.apps.esign.po.signer.DefaultSignerBuilder;
import com.seeyon.apps.esign.po.signer.Signer;
import com.seeyon.apps.ext.workflow.vo.FieldDataVo;
import com.seeyon.apps.ext.workflow.vo.FormDataVo;
import com.seeyon.ctp.common.AppContext;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class FlowFormSignParamBuildFactory implements SignParamBuildFactory {
private EsignConfigProvider configProvider = EsignConfigProvider.getInstance();
private EsignUploadFileService uploadFileService = (EsignUploadFileService) AppContext.getBean("esignUploadFileService");
@Override
public Map<String, Object> buildParam(SignParamSource source) throws Exception {
Map<String, Object> signParams = new HashMap<>();
List<String> fileIds = null;
if (source.isByFile()) {
String attachmentId = source.getSignFileRefId();
if (attachmentId == null) throw new RuntimeException("合同文件不能为空");
List<Map<String, Object>> docs = buildDocs(attachmentId);
fileIds = new ArrayList<>();
for (Map<String, Object> doc : docs) {
fileIds.add((String) doc.get("fileId"));
}
signParams.put("docs", docs);
}
Map<String, Object> signFlowConfig = buildSignFlowConfig(source.getContractTitle(),source.getCallbackUrl());
DefaultSignerBuilder signerBuilder = new DefaultSignerBuilder();
List<String> keywords = new ArrayList<>();
keywords.add(configProvider.getBizConfigByKey(EsignConfigConstants.aSignPositionKeyword));
keywords.add(configProvider.getBizConfigByKey(EsignConfigConstants.bSignPositionKeyword));
keywords.add(configProvider.getBizConfigByKey(EsignConfigConstants.lpSignPositionKeyword));
List<Signer> signers = signerBuilder.buildAll(fileIds,getKeywordPos(fileIds,keywords),source.getSignerParties());
signParams.put("signFlowConfig", signFlowConfig);
signParams.put("signers", signers);
return signParams;
}
@Override
public boolean support(SignParamSource source) {
return source instanceof FlowParamSource;
}
private List<Object> getKeywordPos(List<String> fileIds,List<String> keywords){
List<Object> pos = new ArrayList<>();
for (String fileId : fileIds){
List<Object> signPosition = uploadFileService.getSignPosition(fileId, keywords);
pos.addAll(signPosition);
}
return pos;
}
/**
* 构建文档列表
* @param attachmentId 如果 byFile=true则上传并返回 fileId
*/
public List<Map<String, Object>> buildDocs(String attachmentId) throws Exception {
List<String> fileIds = uploadFileService.uploadFileToEsign(attachmentId);
List<Map<String, Object>> docs = new ArrayList<>();
for (String fileId : fileIds) {
Map<String, Object> docMap = new HashMap<>();
docMap.put("fileId", fileId);
docs.add(docMap);
}
Thread.sleep(1000); // e签宝要求可考虑异步
return docs;
}
public Map<String, Object> buildSignFlowConfig(String contractName,String callbackUrl) throws Exception {
if (contractName == null) throw new RuntimeException("合同名称不能为空");
String signCallBackUrl = configProvider.getBizConfigByKey(EsignConfigConstants.OA_HOST) + callbackUrl;
Map<String, Object> config = new HashMap<>();
config.put("signFlowTitle", contractName);
config.put("autoFinish", true);
config.put("notifyUrl", signCallBackUrl);
Map<String, Object> noticeConfig = new HashMap<>();
noticeConfig.put("noticeTypes", "1");
config.put("noticeConfig", noticeConfig);
Map<String, Object> signConfig = new HashMap<>();
signConfig.put("showBatchDropSealButton", false);
config.put("signConfig", signConfig);
return config;
}
private String getStringField(FormDataVo vo, String field) {
try {
FieldDataVo fieldData = vo.getFieldData(field);
return fieldData.getStringValue();
}catch (Exception e) {
return null;
}
}
}

View File

@@ -0,0 +1,88 @@
package com.seeyon.apps.esign.service;
import com.seeyon.apps.esign.config.EsignConfigProvider;
import com.seeyon.apps.esign.constants.EsignConfigConstants;
import com.seeyon.apps.esign.po.param.JsonParamSource;
import com.seeyon.apps.esign.po.signer.DefaultSignerBuilder;
import com.seeyon.apps.esign.po.signer.Signer;
import com.seeyon.apps.ext.workflow.vo.FieldDataVo;
import com.seeyon.apps.ext.workflow.vo.FormDataVo;
import com.seeyon.ctp.common.AppContext;
import java.util.*;
public class NormalFormSignParamBuildFactory implements SignParamBuildFactory {
private EsignConfigProvider configProvider = EsignConfigProvider.getInstance();
private EsignUploadFileService uploadFileService = (EsignUploadFileService) AppContext.getBean("esignUploadFileService");
@Override
public Map<String, Object> buildParam(SignParamSource source) throws Exception {
Map<String, Object> signParams = new HashMap<>();
List<String> fileIds = null;
if (source.isByFile()) {
String attachmentId = source.getSignFileRefId();
if (attachmentId == null) throw new RuntimeException("合同文件不能为空");
List<Map<String, Object>> docs = buildDocs(attachmentId);
fileIds = new ArrayList<>();
for (Map<String, Object> doc : docs) {
fileIds.add((String) doc.get("fileId"));
}
signParams.put("docs", docs);
}
Map<String, Object> signFlowConfig = buildSignFlowConfig(source.getContractTitle(),source.getCallbackUrl());
DefaultSignerBuilder signerBuilder = new DefaultSignerBuilder();
List<Signer> signers = signerBuilder.buildAll(fileIds,null,source.getSignerParties());
signParams.put("signFlowConfig", signFlowConfig);
signParams.put("signers", signers);
return signParams;
}
@Override
public boolean support(SignParamSource source) {
return source instanceof JsonParamSource;
}
/**
* 构建文档列表
* @param attachmentId 如果 byFile=true则上传并返回 fileId
*/
public List<Map<String, Object>> buildDocs(String attachmentId) throws Exception {
List<String> fileIds = uploadFileService.uploadFileToEsign(attachmentId);
List<Map<String, Object>> docs = new ArrayList<>();
for (String fileId : fileIds) {
Map<String, Object> docMap = new HashMap<>();
docMap.put("fileId", fileId);
docs.add(docMap);
}
Thread.sleep(1000); // e签宝要求可考虑异步
return docs;
}
public Map<String, Object> buildSignFlowConfig(String contractName,String callbackUrl) throws Exception {
if (contractName == null) throw new RuntimeException("合同名称不能为空");
String signCallBackUrl = configProvider.getBizConfigByKey(EsignConfigConstants.OA_HOST) + callbackUrl;
Map<String, Object> config = new HashMap<>();
config.put("signFlowTitle", contractName);
config.put("autoFinish", true);
config.put("notifyUrl", signCallBackUrl);
Map<String, Object> noticeConfig = new HashMap<>();
noticeConfig.put("noticeTypes", "1");
config.put("noticeConfig", noticeConfig);
Map<String, Object> signConfig = new HashMap<>();
signConfig.put("showBatchDropSealButton", false);
config.put("signConfig", signConfig);
return config;
}
private String getStringField(FormDataVo vo, String field) {
try {
FieldDataVo fieldData = vo.getFieldData(field);
return fieldData.getStringValue();
}catch (Exception e) {
return null;
}
}
}

View File

@@ -0,0 +1,122 @@
package com.seeyon.apps.esign.service;
import cn.hutool.json.JSONObject;
import com.cedarsoftware.util.io.JsonObject;
import com.seeyon.aicloud.common.JsonUtils;
import com.seeyon.apps.esign.config.EsignConfigProvider;
import com.seeyon.apps.esign.constants.EsignApiUrl;
import com.seeyon.apps.esign.constants.EsignConfigConstants;
import com.seeyon.apps.esign.po.esignapi.EsignApiHeader;
import com.seeyon.apps.esign.po.esignapi.EsignBaseResp;
import com.seeyon.apps.esign.po.seal.SealInfoVo;
import com.seeyon.apps.esign.utils.HttpClient;
import com.seeyon.ctp.common.AppContext;
import com.seeyon.ctp.services.ServiceException;
import com.seeyon.utils.form.*;
import com.seeyon.v3x.services.form.FormFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.*;
public class SealService {
private static final Log log = LogFactory.getLog(SealService.class);
private EsignConfigProvider configProvider = EsignConfigProvider.getInstance();
private FormFactory formFactory;
public FormFactory getFormFactory() {
if (formFactory == null) {
formFactory = (FormFactory) AppContext.getBean("formFactory");
}
return formFactory;
}
public void grantSeal(Map<String, Object> params) throws Exception {
JsonObject reqParams = new JsonObject();
String sealId = getSealId((String) params.get("orgId"), (String) params.get("sealName"));
reqParams.put("sealId", sealId);
List<String> authorizedPsnIds = new ArrayList<>();
authorizedPsnIds.add((String) params.get("accountId"));
reqParams.put("authorizedPsnIds", authorizedPsnIds);
reqParams.put("sealRole", "SEAL_USER");
reqParams.put("transactorPsnId", params.get("managerId"));
JSONObject sealAuthScope = new JSONObject();
List<String> templateIds = new ArrayList<>();
templateIds.add("ALL");
sealAuthScope.put("templateIds", templateIds);
reqParams.put("sealAuthScope", sealAuthScope);
EsignApiHeader esignApiHeader = EsignApiHeader.build();
esignApiHeader.appId(configProvider.getBizConfigByKey(EsignConfigConstants.APP_ID))
.httpMethod("POST")
.heads("")
.pathAndParameters(EsignApiUrl.SEAL_GRANT_URL)
.contentMD5(reqParams.toString())
.signature(configProvider.getBizConfigByKey(EsignConfigConstants.APP_SECRET));
String url = configProvider.getBizConfigByKey(EsignConfigConstants.ESIGN_HOST) + EsignApiUrl.SEAL_GRANT_URL;
HttpClient.httpPostRaw(url, reqParams.toString(), esignApiHeader.convert2Headers(), null);
}
private String getSealId(String orgId, String sealName) throws Exception {
String host = configProvider.getBizConfigByKey(EsignConfigConstants.ESIGN_HOST);
int pageNo = 1;
int pageSize = 20;
EsignApiHeader esignApiHeader = EsignApiHeader.build();
esignApiHeader.appId(configProvider.getBizConfigByKey(EsignConfigConstants.APP_ID))
.httpMethod("GET")
.heads("")
.pathAndParameters(EsignApiUrl.SEAL_QUERY_URL + "?" + HttpClient.sortQueryString("orgId=" + orgId + "&pageNo=" + pageNo + "&pageSize=" + pageSize))
.contentMD5("")
.signature(configProvider.getBizConfigByKey(EsignConfigConstants.APP_SECRET));
String url = host + EsignApiUrl.SEAL_QUERY_URL + "?orgId=" + orgId + "&pageNo=" + pageNo + "&pageSize=" + pageSize;
String respStr = HttpClient.httpGet(url, esignApiHeader.convert2Headers(), "UTF-8");
EsignBaseResp esignBaseResp = JsonUtils.parseObject(respStr, EsignBaseResp.class);
Map<String, Object> data = (Map<String, Object>) esignBaseResp.getData();
LinkedList<Object> seals = (LinkedList<Object>) data.get("seals");
for (Object seal : seals) {
Map<String, Object> sealMap = (Map<String, Object>) seal;
if (sealMap.get("sealName").equals(sealName)) {
return (String) sealMap.get("sealId");
}
}
return null;
}
public void upsertOaSealDoc(SealInfoVo vo) {
String formNo = configProvider.getBizConfigByKey(EsignConfigConstants.sealInfoFormCode);
List<FormWhereCondition> conditions = new ArrayList<>();
conditions.add(FormWhereCondition.build().display("印章ID").value(vo.getSealId()));
FormColumn formColumn = null;
TableContext master = null;
try {
master = FormTableExecutor.master(formNo);
formColumn = FormTableExecutor.queryOne(master,conditions,true);
} catch (Exception e) {
log.error("查询印章信息失败: " + e.getMessage(), e);
}
if (formColumn == null) {
if ("已启用".equals(vo.getStatusDescription())) {
Map<String, Object> params = new HashMap<>();
params.put("印章ID", vo.getSealId());
params.put("印章名称", vo.getSealName());
params.put("印章类型", vo.getSealBizTypeDescription());
params.put("印章状态", vo.getStatusDescription());
// params.put("印章图片地址",vo.getSealImageDownloadUrl());
try {
FormSaveUtil.formSave(configProvider.getBizConfigByKey(EsignConfigConstants.formLoginName),configProvider.getBizConfigByKey(EsignConfigConstants.sealInfoFormCode),formFactory,params,null);
} catch (ServiceException e) {
log.error(vo.getSealName() + "信息写入OA档案失败," + e.getMessage(), e);
}
}
} else {
if (!"已启用".equals(vo.getStatusDescription()) && master != null) {
try {
FormTableExecutor.delete(master,conditions);
} catch (Exception e) {
log.error("删除停用印章失败" + e.getMessage(), e);
}
}
}
}
}

View File

@@ -0,0 +1,150 @@
package com.seeyon.apps.esign.service;
import com.seeyon.aicloud.common.JsonUtils;
import com.seeyon.apps.esign.config.EsignConfigProvider;
import com.seeyon.apps.esign.constants.EsignApiUrl;
import com.seeyon.apps.esign.constants.EsignConfigConstants;
import com.seeyon.apps.esign.po.esignapi.EsignApiHeader;
import com.seeyon.apps.esign.po.esignapi.EsignBaseResp;
import com.seeyon.apps.ext.workflow.vo.FormDataVo;
import com.seeyon.cap4.form.bean.FormDataMasterBean;
import com.seeyon.ctp.common.AppContext;
import com.seeyon.ctp.util.JDBCAgent;
import com.seeyon.utils.http.HttpClient;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import www.seeyon.com.utils.UUIDUtil;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class SignLinkService {
private static final Log log = LogFactory.getLog(SignLinkService.class);
private EsignConfigProvider esignConfigProvider = (EsignConfigProvider) AppContext.getBean("esignConfigProvider");
private TokenCacheManager tokenCacheManager = (TokenCacheManager) AppContext.getBean("tokenCacheManager");
public void saveGetLinkParam(FormDataVo formDataVo, FormDataMasterBean formDataMasterBean,String eFlowId) {
try {
String bSignerType = formDataVo.getFieldData("乙方签署类型").getStringValue();
String psnAccount = null;
if(!"组织".equals(bSignerType) ) {
psnAccount = formDataVo.getFieldData("乙方电话").getStringValue();
}else {
psnAccount = formDataVo.getFieldData("乙方经办人手机号").getStringValue();
}
String contractNo = formDataVo.getFieldData("合同编号").getStringValue();
Map<String,Object> param = new HashMap<>();
Map<String,Object> operator = new HashMap<>();
operator.put("psnAccount",psnAccount);
param.put("signFlowId",eFlowId);
param.put("operator",operator);
String paramStr = JsonUtils.toJSONString(param);
saveDb(paramStr,eFlowId,contractNo);
}catch (Exception e) {
log.error(e.getMessage(),e);
}
}
public void del(String eFlowId) {
String sqlDel = "delete FROM SIGN_LINK_PARAM where eFlowId = ?";
JDBCAgent jdbcAgent = new JDBCAgent();
try {
List<Object> param = new ArrayList<>();
param.add(eFlowId);
jdbcAgent.execute(sqlDel,param);
}catch (Exception e) {
log.error(e.getMessage(),e);
}finally {
jdbcAgent.close();
}
}
private void saveDb(String jsonStr,String eFlowId,String contractNo) {
String sqlInsert = "insert into SIGN_LINK_PARAM (id,param,eFlowId,contractNo) values (?,?,?,?)";
String sqlQuery = "select * FROM SIGN_LINK_PARAM where contractNo = ?";
String sqlUpdate = "update SIGN_LINK_PARAM set param = ?,eFlowId = ? where id = ?";
JDBCAgent jdbcAgent = new JDBCAgent();
try {
List<Object> param = new ArrayList<>();
param.add(contractNo);
jdbcAgent.execute(sqlQuery,param);
List list = jdbcAgent.resultSetToList();
long id = UUIDUtil.getUUIDLong();
if(list.size() == 0) {
param.clear();
param.add(id);
param.add(jsonStr);
param.add(eFlowId);
param.add(contractNo);
jdbcAgent.execute(sqlInsert,param);
}else {
param.clear();
Map<String,Object> tempMap = (Map<String, Object>) list.get(0);
param.add(jsonStr);
param.add(eFlowId);
param.add(tempMap.get("id"));
jdbcAgent.execute(sqlUpdate,param);
}
}catch (Exception e) {
log.error(e.getMessage(),e);
}finally {
jdbcAgent.close();
}
}
public String getSignLink(String eFlowId) {
String sqlQuery = "select * from SIGN_LINK_PARAM where eFlowId = ?";
JDBCAgent jdbcAgent = new JDBCAgent();
try {
List<Object> param = new ArrayList<>();
param.add(eFlowId);
jdbcAgent.execute(sqlQuery,param);
List list = jdbcAgent.resultSetToList();
if(list.size() > 0) {
Map<String,Object> tempMap = (Map<String, Object>) list.get(0);
String paramStr = (String)tempMap.get("param");
if(!checkContractVaild(eFlowId)) {
throw new RuntimeException("当前合同无效");
}
String url = esignConfigProvider.getBizConfigByKey(EsignConfigConstants.ESIGN_HOST) + EsignApiUrl.SIGN_LINK_GET_URL.replace("{signFlowId}",eFlowId);
EsignApiHeader esignApiHeader = EsignApiHeader.build();
esignApiHeader.token(tokenCacheManager.getToken()).appId(esignConfigProvider.getBizConfigByKey(EsignConfigConstants.APP_ID));
String respStr = HttpClient.httpPostRaw(url, paramStr,esignApiHeader.convert2Headers(), "UTF-8");
EsignBaseResp esignBaseResp = JsonUtils.parseObject(respStr, EsignBaseResp.class);
Map<String,Object> dataMap = (Map<String, Object>) esignBaseResp.getData();
if(!"0".equals(esignBaseResp.getCode() + "")) {
log.error("合同链接获取失败," + esignBaseResp.getMessage());
}else {
return (String) dataMap.get("url");
}
}
}catch (Exception e) {
log.error("合同链接获取失败:"+e.getMessage(),e);
}finally {
jdbcAgent.close();
}
return null;
}
private boolean checkContractVaild(String eFlowId) {
EsignApiHeader esignApiHeader = EsignApiHeader.build();
esignApiHeader.token(tokenCacheManager.getToken()).appId(esignConfigProvider.getBizConfigByKey(EsignConfigConstants.APP_ID));
String url = esignConfigProvider.getBizConfigByKey(EsignConfigConstants.ESIGN_HOST) + EsignApiUrl.SIGN_FLOW_QUERY.replace("{signFlowId}",eFlowId);
String respStr = HttpClient.httpGet(url, esignApiHeader.convert2Headers(), "UTF-8");
EsignBaseResp esignBaseResp = JsonUtils.parseObject(respStr, EsignBaseResp.class);
Map<String,Object> dataMap = (Map<String, Object>) esignBaseResp.getData();
if(!"0".equals(esignBaseResp.getCode() + "")) {
log.error("合同信息查询失败," + esignBaseResp.getMessage());
return false;
}
Integer flowStatus = (Integer) dataMap.get("signFlowStatus");
return flowStatus == 1;
}
}

View File

@@ -0,0 +1,15 @@
package com.seeyon.apps.esign.service;
import java.util.Map;
public interface SignParamBuildFactory {
/**
* 构建签署
* @param source
* @return
*/
Map<String, Object> buildParam(SignParamSource source) throws Exception;
boolean support(SignParamSource source);
}

View File

@@ -0,0 +1,51 @@
package com.seeyon.apps.esign.service;
import com.seeyon.apps.esign.po.signer.SignParty;
import java.util.List;
public interface SignParamSource {
/* ================= 文档相关 ================= */
/** 合同标题 */
String getContractTitle();
/** 是否通过附件生成文件 */
boolean isByFile();
/* ================= 签署流 / 回调 ================= */
/** 业务唯一标识(回调使用) */
String getBizFormId();
/** 业务表名 */
String getTableName();
String getSignFileRefId();
/** 盖章后附件字段 */
String getSignedFileField();
/** 签署状态字段 */
String getSignStatusField();
/** 签署状态枚举值 */
Long getSignStatusEnumId();
boolean autoSign();
/* ================= 签署方编排(核心) ================= */
String getCallbackUrl();
/**
* 所有签署方(顺序、类型、自动签等都在这里)
*/
List<SignParty> getSignerParties();
/** 通知类型 */
default String noticeTypes() {
return "1";
}
}

View File

@@ -0,0 +1,98 @@
package com.seeyon.apps.esign.service;
import com.seeyon.aicloud.common.JsonUtils;
import com.seeyon.apps.esign.config.EsignConfigProvider;
import com.seeyon.apps.esign.constants.EsignApiUrl;
import com.seeyon.apps.esign.constants.EsignConfigConstants;
import com.seeyon.apps.esign.po.esignapi.EsignApiHeader;
import com.seeyon.apps.esign.po.esignapi.EsignBaseResp;
import com.seeyon.apps.esign.po.esignapi.EsignToken;
import com.seeyon.apps.esign.utils.HttpClient;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
public class TokenCacheManager {
private EsignConfigProvider esignConfigProvider = EsignConfigProvider.getInstance();
private final AtomicReference<EsignToken> tokenRef = new AtomicReference<>();
private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
private static final long CHECK_INTERVAL = 2 * 60 * 60 * 1000; // 120分钟检查一次
public TokenCacheManager() {
// 启动定期检查任务
scheduler.scheduleAtFixedRate(this::checkTokenExpiry,
CHECK_INTERVAL, CHECK_INTERVAL, TimeUnit.MILLISECONDS);
}
private boolean checkExpired(String token) {
EsignApiHeader esignApiHeader = EsignApiHeader.build();
try {
esignApiHeader.token(token).appId(esignConfigProvider.getBizConfigByKey(EsignConfigConstants.APP_ID));
} catch (Exception e) {
e.printStackTrace();
}
//获取orgId
String queryStr = EsignApiUrl.QUERY_ORGINFO + "?orgName=" + esignConfigProvider.getBizConfigByKey(EsignConfigConstants.UNITNAME);
String reqUrl = esignConfigProvider.getBizConfigByKey(EsignConfigConstants.ESIGN_HOST) + queryStr;
String orgInfoRespStr = HttpClient.httpGet(reqUrl, esignApiHeader.convert2Headers(), "UTF-8");
EsignBaseResp orgInfoResp = JsonUtils.parseObject(orgInfoRespStr, EsignBaseResp.class);
if(orgInfoResp.getCode() == 401) {
return true;
}
return false;
}
public String getToken() {
EsignToken current = tokenRef.get();
if (current != null && !checkExpired(current.getTokenStr())) {
return current.getTokenStr();
}
return refreshToken();
}
private String refreshToken() {
EsignToken newToken = fetchNewToken();
tokenRef.set(newToken);
return newToken.getTokenStr();
}
private void checkTokenExpiry() {
EsignToken current = tokenRef.get();
if (current != null && isTokenExpired(current)) {
refreshToken();
}
}
private boolean isTokenExpired(EsignToken token) {
return System.currentTimeMillis() >= token.getTtl();
}
private EsignToken fetchNewToken() {
// 实际获取token的逻辑
String queryStr = "?appId=" + esignConfigProvider.getBizConfigByKey(EsignConfigConstants.APP_ID) + "&secret=" + esignConfigProvider.getBizConfigByKey(EsignConfigConstants.APP_SECRET) + "&grantType=client_credentials";
String url = esignConfigProvider.getBizConfigByKey(EsignConfigConstants.ESIGN_HOST) + EsignApiUrl.TOKEN_GET_URL + queryStr;
String respStr = HttpClient.httpGet(url, null, null);
EsignBaseResp esignBaseResp = JsonUtils.parseObject(respStr, EsignBaseResp.class);
if(esignBaseResp.getCode() != 0) {
throw new RuntimeException("获取e签宝token失败");
}
Map<String,Object> dataMap = (Map<String, Object>) esignBaseResp.getData();
String token = (String) dataMap.get("token");
Long ttl = Long.parseLong((String) dataMap.get("expiresIn")) ;
String refreshToken = (String) dataMap.get("refreshToken");
EsignToken esignToken = new EsignToken();
esignToken.setTokenStr(token);
esignToken.setTtl(ttl);
esignToken.setRefreshToken(refreshToken);
return esignToken;
}
public void shutdown() {
scheduler.shutdown();
}
}

View File

@@ -0,0 +1,17 @@
package com.seeyon.apps.esign.utils;
import java.util.Map;
public class EnHancedMap {
private Map<String,Object> map;
public EnHancedMap of(String key, Object value) {
map.put(key, value);
return this;
}
public Map<String,Object> getMap() {
return map;
}
}

View File

@@ -0,0 +1,471 @@
package com.seeyon.apps.esign.utils;
import com.seeyon.apps.esign.po.esignapi.EsignException;
import com.seeyon.apps.esign.po.esignapi.EsignHttpResponse;
import org.apache.http.*;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.net.ssl.*;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.UnknownHostException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
/**
* @description Http请求 辅助类
* @author 澄泓
* @since JDK1.7
*/
public class EsignHttpCfgHelper {
private static Logger LOGGER = LoggerFactory.getLogger(EsignHttpCfgHelper.class);
/**
* 超时时间,默认15000毫秒
*/
private static int MAX_TIMEOUT = 15000;
/**
* 请求池最大连接数,默认100个
*/
private static int MAX_TOTAL=100;
/**
* 单域名最大的连接数,默认50个
*/
private static int ROUTE_MAX_TOTAL=50;
/**
* 请求失败重试次数,默认3次
*/
private static int MAX_RETRY = 3;
/**
* 是否需要域名校验,默认不需要校验
*/
private static boolean SSL_VERIFY=false;
/**
* 正向代理IP
*/
private static String PROXY_IP;
/**
* 正向代理端口,默认8888
*/
private static int PROXY_PORT=8888;
/**
* 代理协议,默认http
*/
private static String PROXY_AGREEMENT="http";
/**
* 是否开启代理默认false
*/
private static boolean OPEN_PROXY=false;
/**
* 代理服务器用户名
*/
private static String PROXY_USERNAME="";
/**
* 代理服务器密码
*/
private static String PROXY_PASSWORD="";
private static PoolingHttpClientConnectionManager connMgr; //连接池
private static HttpRequestRetryHandler retryHandler; //重试机制
private static CloseableHttpClient httpClient=null;
public static int getMaxTimeout() {
return MAX_TIMEOUT;
}
public static void setMaxTimeout(int maxTimeout) {
MAX_TIMEOUT = maxTimeout;
}
public static int getMaxTotal() {
return MAX_TOTAL;
}
public static void setMaxTotal(int maxTotal) {
MAX_TOTAL = maxTotal;
}
public static int getRouteMaxTotal() {
return ROUTE_MAX_TOTAL;
}
public static void setRouteMaxTotal(int routeMaxTotal) {
ROUTE_MAX_TOTAL = routeMaxTotal;
}
public static int getMaxRetry() {
return MAX_RETRY;
}
public static void setMaxRetry(int maxRetry) {
MAX_RETRY = maxRetry;
}
public static boolean isSslVerify() {
return SSL_VERIFY;
}
public static void setSslVerify(boolean sslVerify) {
SSL_VERIFY = sslVerify;
}
public static String getProxyIp() {
return PROXY_IP;
}
public static void setProxyIp(String proxyIp) {
PROXY_IP = proxyIp;
}
public static int getProxyPort() {
return PROXY_PORT;
}
public static void setProxyPort(int proxyPort) {
PROXY_PORT = proxyPort;
}
public static String getProxyAgreement() {
return PROXY_AGREEMENT;
}
public static void setProxyAgreement(String proxyAgreement) {
PROXY_AGREEMENT = proxyAgreement;
}
public static boolean getOpenProxy() {
return OPEN_PROXY;
}
public static void setOpenProxy(boolean openProxy) {
OPEN_PROXY = openProxy;
}
public static String getProxyUsername() {
return PROXY_USERNAME;
}
public static void setProxyUserame(String proxyUsername) {
PROXY_USERNAME = proxyUsername;
}
public static String getProxyPassword() {
return PROXY_PASSWORD;
}
public static void setProxyPassword(String proxyPassword) {
PROXY_PASSWORD = proxyPassword;
}
/**
* 不允许外部创建实例
*/
private EsignHttpCfgHelper() {
}
//------------------------------公有方法start--------------------------------------------
/**
* @description 发起HTTP / HTTPS 请求
*
* @param reqType
* {@link EsignRequestType} 请求类型 GET、 POST 、 DELETE 、 PUT
* @param httpUrl
* {@link String} 请求目标地址
* @param headers
* {@link Map} 请求头
* @param param
* {@link Object} 参数
* @return
* @throws EsignException
* @author 澄泓
*/
public static EsignHttpResponse sendHttp(EsignRequestType reqType, String httpUrl, Map<String, String> headers, Object param, boolean debug)
throws EsignException {
HttpRequestBase reqBase=null;
if(httpUrl.startsWith("http")){
reqBase=reqType.getHttpType(httpUrl);
}else{
throw new EsignException("请求url地址格式错误");
}
if(debug){
LOGGER.info("请求头:{}",headers+"\n");
LOGGER.info("请求参数\n{}", param+"\n");
LOGGER.info("请求地址\n:{}\n请求方式\n:{}",reqBase.getURI(),reqType+"\n");
}
//请求方法不是GET或者DELETE时传入body体否则不传入。
String[] methods = {"DELETE", "GET"};
if(param instanceof String&&Arrays.binarySearch(methods, reqType.name())<0){//POST或者PUT请求
((HttpEntityEnclosingRequest) reqBase).setEntity(
new StringEntity(String.valueOf(param), ContentType.create("application/json", "UTF-8")));
}
//参数时字节流数组
else if(param instanceof byte[]) {
reqBase=reqType.getHttpType(httpUrl);
byte[] paramBytes = (byte[])param;
((HttpEntityEnclosingRequest) reqBase).setEntity(new ByteArrayEntity(paramBytes));
}
//参数是form表单时
else if(param instanceof List){
((HttpEntityEnclosingRequest) reqBase).setEntity(new UrlEncodedFormEntity((Iterable<? extends NameValuePair>) param));
}
httpClient = getHttpClient();
config(reqBase);
//设置请求头
if(headers != null &&headers.size()>0) {
for(Map.Entry<String, String> entry :headers.entrySet()) {
reqBase.setHeader(entry.getKey(), entry.getValue());
}
}
//响应对象
CloseableHttpResponse res = null;
//响应内容
String resCtx = null;
int status;
EsignHttpResponse esignHttpResponse = new EsignHttpResponse();
try {
//执行请求
res = httpClient.execute(reqBase);
status=res.getStatusLine().getStatusCode();
//获取请求响应对象和响应entity
HttpEntity httpEntity = res.getEntity();
if(httpEntity != null) {
resCtx = EntityUtils.toString(httpEntity,"utf-8");
}
if(debug) {
LOGGER.info("响应\n{}", resCtx + "\n");
LOGGER.info("----------------------------end------------------------");
}
} catch (NoHttpResponseException e) {
throw new EsignException("服务器丢失了",e);
} catch (SSLHandshakeException e){
String msg = MessageFormat.format("SSL握手异常", e);
EsignException ex = new EsignException(msg, e);
throw ex;
} catch (UnknownHostException e){
EsignException ex = new EsignException("服务器找不到", e);
ex.initCause(e);
throw ex;
} catch(ConnectTimeoutException e){
EsignException ex = new EsignException("连接超时", e);
ex.initCause(e);
throw ex;
} catch(SSLException e){
EsignException ex = new EsignException("SSL异常",e);
ex.initCause(e);
throw ex;
} catch (ClientProtocolException e) {
EsignException ex = new EsignException("请求头异常",e);
ex.initCause(e);
throw ex;
} catch (IOException e) {
EsignException ex = new EsignException("网络请求失败",e);
ex.initCause(e);
throw ex;
} finally {
if(res != null) {
try {
res.close();
} catch (IOException e) {
EsignException ex = new EsignException("--->>关闭请求响应失败",e);
ex.initCause(e);
throw ex;
}
}
}
esignHttpResponse.setStatus(status);
esignHttpResponse.setBody(resCtx);
return esignHttpResponse;
}
//------------------------------公有方法end----------------------------------------------
//------------------------------私有方法start--------------------------------------------
/**
* @description 请求头和超时时间配置
*
* @param httpReqBase
* @author 澄泓
*/
private static void config(HttpRequestBase httpReqBase) {
// 配置请求的超时设置
RequestConfig.Builder builder = RequestConfig.custom()
.setConnectionRequestTimeout(MAX_TIMEOUT)
.setConnectTimeout(MAX_TIMEOUT)
.setSocketTimeout(MAX_TIMEOUT);
if(OPEN_PROXY){
HttpHost proxy=new HttpHost(PROXY_IP,PROXY_PORT,PROXY_AGREEMENT);
builder.setProxy(proxy);
}
RequestConfig requestConfig = builder.build();
httpReqBase.setConfig(requestConfig);
}
/**
* @description 连接池配置
*
* @return
* @author 澄泓
*/
private static void cfgPoolMgr() throws EsignException {
ConnectionSocketFactory plainsf = PlainConnectionSocketFactory.getSocketFactory();
LayeredConnectionSocketFactory sslsf = SSLConnectionSocketFactory.getSocketFactory();
if(!SSL_VERIFY){
sslsf=sslConnectionSocketFactory();
}
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", plainsf)
.register("https", sslsf)
.build();
//连接池管理器
connMgr = new PoolingHttpClientConnectionManager(registry);
//请求池最大连接数
connMgr.setMaxTotal(MAX_TOTAL);
//但域名最大的连接数
connMgr.setDefaultMaxPerRoute(ROUTE_MAX_TOTAL);
}
/**
* @description 设置重试机制
*
* @author 澄泓
*/
private static void cfgRetryHandler() {
retryHandler = new HttpRequestRetryHandler() {
@Override
public boolean retryRequest(IOException e, int excCount, HttpContext ctx) {
//超过最大重试次数,就放弃
if(excCount > MAX_RETRY) {
return false;
}
//服务器丢掉了链接,就重试
if(e instanceof NoHttpResponseException) {
return true;
}
//不重试SSL握手异常
if(e instanceof SSLHandshakeException) {
return false;
}
//中断
if(e instanceof InterruptedIOException) {
return false;
}
//目标服务器不可达
if(e instanceof UnknownHostException) {
return false;
}
//连接超时
//SSL异常
if(e instanceof SSLException) {
return false;
}
HttpClientContext clientCtx = HttpClientContext.adapt(ctx);
HttpRequest req = clientCtx.getRequest();
//如果是幂等请求,就再次尝试
if(!(req instanceof HttpEntityEnclosingRequest)) {
return true;
}
return false;
}
};
}
/**
* 忽略域名校验
*/
private static SSLConnectionSocketFactory sslConnectionSocketFactory() throws EsignException {
try {
SSLContext ctx = SSLContext.getInstance("TLS"); // 创建一个上下文(此处指定的协议类型似乎不是重点)
X509TrustManager tm = new X509TrustManager() { // 创建一个跳过SSL证书的策略
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
}
};
ctx.init(null, new TrustManager[] { tm }, null); // 使用上面的策略初始化上下文
return new SSLConnectionSocketFactory(ctx, new String[] { "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2" }, null, NoopHostnameVerifier.INSTANCE);
}catch (Exception e){
EsignException ex = new EsignException("忽略域名校验失败",e);
ex.initCause(e);
throw ex;
}
}
/**
* @description 获取单例HttpClient
*
* @return
* @author 澄泓
*/
private static synchronized CloseableHttpClient getHttpClient() throws EsignException {
if(httpClient==null) {
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(new AuthScope(PROXY_IP,PROXY_PORT),new UsernamePasswordCredentials(PROXY_USERNAME, PROXY_PASSWORD));
cfgPoolMgr();
cfgRetryHandler();
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
httpClient = httpClientBuilder.setDefaultCredentialsProvider(credsProvider).setConnectionManager(connMgr).setRetryHandler(retryHandler).build();
}
return httpClient;
}
//------------------------------私有方法end----------------------------------------------
}

View File

@@ -0,0 +1,83 @@
package com.seeyon.apps.esign.utils;
import com.seeyon.apps.esign.po.esignapi.EsignException;
import com.seeyon.apps.esign.po.esignapi.EsignHttpResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
/**
* @description Http 请求 辅助类
* @author 澄泓
* @since JDK1.7
*/
public class EsignHttpHelper {
private static final Logger LOGGER = LoggerFactory.getLogger(EsignHttpHelper.class);
/**
* 不允许外部创建实例
*/
private EsignHttpHelper() {
}
/**
* @description 发送常规HTTP 请求
*
* @param reqType 请求方式
* @param url 请求路径
* @param paramStr 请求参数
* @return
* @throws EsignException
* @author 澄泓
*/
public static EsignHttpResponse doCommHttp(String host, String url, EsignRequestType reqType, Object paramStr , Map<String,String> httpHeader, boolean debug) throws EsignException {
return EsignHttpCfgHelper.sendHttp(reqType, host+url,httpHeader, paramStr, debug);
}
/**
* @description 发送文件流上传 HTTP 请求
*
* @param reqType 请求方式
* @param uploadUrl 请求路径
* @param param 请求参数
* @param fileContentMd5 文件fileContentMd5
* @param contentType 文件MIME类型
* @return
* @author 澄泓
*/
public static EsignHttpResponse doUploadHttp( String uploadUrl,EsignRequestType reqType,byte[] param, String fileContentMd5,
String contentType, boolean debug) throws EsignException {
Map<String, String> uploadHeader = buildUploadHeader(fileContentMd5, contentType);
if(debug){
LOGGER.info("----------------------------start------------------------");
LOGGER.info("fileContentMd5:{}",fileContentMd5);
LOGGER.info("contentType:{}",contentType);
}
return EsignHttpCfgHelper.sendHttp(reqType,uploadUrl, uploadHeader, param,debug);
}
/**
* @description 创建文件流上传 请求头
*
* @param fileContentMd5
* @param contentType
* @return
* @author 澄泓
*/
public static Map<String, String> buildUploadHeader(String fileContentMd5, String contentType) {
Map<String, String> header = new HashMap<>();
header.put("Content-MD5", fileContentMd5);
header.put("Content-Type", contentType);
return header;
}
// ------------------------------私有方法end----------------------------------------------
}

View File

@@ -0,0 +1,38 @@
package com.seeyon.apps.esign.utils;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
public enum EsignRequestType {
POST{
@Override
public HttpRequestBase getHttpType(String url) {
return new HttpPost(url);
}
},
GET{
@Override
public HttpRequestBase getHttpType(String url) {
return new HttpGet(url);
}
},
DELETE{
@Override
public HttpRequestBase getHttpType(String url) {
return new HttpDelete(url);
}
},
PUT{
@Override
public HttpRequestBase getHttpType(String url) {
return new HttpPut(url);
}
},
;
public abstract HttpRequestBase getHttpType(String url);
}

View File

@@ -0,0 +1,516 @@
package com.seeyon.apps.esign.utils;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.seeyon.ctp.common.AppContext;
import com.seeyon.ctp.common.SystemEnvironment;
import com.seeyon.ctp.common.exceptions.BusinessException;
import com.seeyon.ctp.common.filemanager.manager.AttachmentManager;
import com.seeyon.ctp.common.filemanager.manager.FileManager;
import com.seeyon.ctp.common.po.filemanager.Attachment;
import com.seeyon.ctp.organization.bo.V3xOrgAccount;
import com.seeyon.ctp.organization.bo.V3xOrgMember;
import com.seeyon.ctp.organization.manager.OrgManager;
import com.seeyon.ctp.services.FileUploadExporter;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import www.seeyon.com.utils.StringUtil;
import www.seeyon.com.utils.UUIDUtil;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;
public class FileUtil {
private static final long MAX_FILE_SIZE = 100 * 1024 * 1024; // 100MB
private static final String TEMP_DIR = System.getProperty("java.io.tmpdir") + File.separator + "seeyontempfile";
private static final String DEFAULT_FILENAME_PREFIX = "没有文件名_";
private static final String CATEGORY_CODE = "66";
private FileManager fileManager;
public void setFileManager(FileManager fileManager) {
this.fileManager = fileManager;
}
public FileManager getFileManager() {
if (fileManager == null) {
fileManager = (FileManager) AppContext.getBean("fileManager");
}
return fileManager;
}
private AttachmentManager attachmentManager;
public void setAttachmentManager(AttachmentManager attachmentManager) {
this.attachmentManager = attachmentManager;
}
public AttachmentManager getAttachmentManager() {
if (attachmentManager == null) {
attachmentManager = (AttachmentManager) AppContext.getBean("attachmentManager");
}
return attachmentManager;
}
public void isFilePath(String filePath) {
File directory = new File(filePath);
if (!directory.exists()) {
directory.mkdirs();
}
}
/**
* 上传附件
*
* @param fileNames
* @throws Exception
* @throws NumberFormatException
*/
public List<Attachment> fileUpload(List<String> fileNames, String summaryId, Long memberId, Long accountId) throws NumberFormatException, Exception {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
FileUploadExporter fileUpload = new FileUploadExporter();
List<Attachment> attachments = new ArrayList<Attachment>();
File f = null;
long l = UUIDUtil.getUUIDLong();
for (int i = 0; i < fileNames.size(); i++) {
String fileName = fileNames.get(i);
if (StringUtils.isNotEmpty(fileName)) {
f = new File(fileName);
if (!f.exists()) {
return null;
}
if (f.length() > 102400000) {
return null;
}
}
String[] strs = new String[]{f.getAbsolutePath()};
String s = fileUpload.processUpload(strs);
Map<String, String> map = new HashMap();
String attachName = f.getName();
String[] suffixNames = attachName.split("\\.");
map.put("type", "0");
map.put("fileUrl", s);
map.put("mimeType", "application/" + suffixNames[suffixNames.length - 1].toLowerCase());
map.put("size", f.length() + "");
map.put("subReference", l + "");
map.put("category", "66");
map.put("createdate", sdf.format(new Date()));
map.put("filename", f.getName());
map.put("reference", summaryId);
Attachment attachment = new Attachment(map);
attachments.add(attachment);
}
String str = getAttachmentManager().create(attachments, memberId, accountId);
return attachments;
}
public List<String> fieldFileDownload(Long refId, String path) throws BusinessException {
// 判断路径是否存在
File file = new File(path);
if (!file.exists()) {
file.mkdirs();
}
List<Long> fileUrls = getAttachmentManager().getBySubReference(refId);
System.out.println(fileUrls.size());
List<String> filepaths = new ArrayList<>();
for (Long fileUrl : fileUrls) {
Attachment attachment = getAttachmentManager().getAttachmentByFileURL(fileUrl);
InputStream inputStream = getFileManager().getFileInputStream(attachment.getFileUrl());
String filepath = path + attachment.getFilename();
try (OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(filepath))) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
outputStream.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
filepaths.add(filepath);
}
return filepaths;
}
public JSONArray getFileContent(String filePath) throws IOException {
JSONArray jsonArray = new JSONArray();
String houzhui = filePath.substring(filePath.lastIndexOf(".") + 1);
// 创建文件输入流
FileInputStream file = new FileInputStream(new File(filePath));
// 创建工作簿对象
Workbook workbook;
System.out.println("当前文件为"+houzhui+"后缀");
if ("xlsx".equals(houzhui) || "XLSX".equals(houzhui)) {
workbook = new XSSFWorkbook(file);
} else {
workbook = new HSSFWorkbook(file);
}
// 获取第一个工作表
Sheet sheet = workbook.getSheetAt(0);
// 迭代行
Iterator<Row> rowIterator = sheet.iterator();
// 根据行跳过设置
row : while (rowIterator.hasNext()) {
Row row = rowIterator.next();
if (row.getRowNum() < 2) {
continue;
}
int num = 0;
int bj = 0;
JSONObject jsonObject = new JSONObject();
JSONArray SPS = new JSONArray();
JSONObject SP = new JSONObject();
boolean isddh = false;
// 迭代单元格
Iterator<Cell> cellIterator = row.cellIterator();
cell : while (cellIterator.hasNext()) {
// 获取单元格对象
Cell cell = cellIterator.next();
// 单元格索引为1的数据订单号
if (cell.getColumnIndex() == 1) {
String ddh = "";
switch (cell.getCellType()) {
case STRING:
ddh = cell.getStringCellValue();
break;
case NUMERIC:
ddh = cell.getNumericCellValue()+"";
break;
default:
ddh = "";
}
// 如果当前订单号为空,则跳过当前行数据
// 查询当前订单号是否已经存在
for (int i = 0; i < jsonArray.size(); i++) {
JSONObject json = jsonArray.getJSONObject(i);
if (ddh.equals(json.getString("DDH"))) {
// 订单号已经存在
bj = i;
isddh = true;
jsonObject = json;
SPS = jsonObject.getJSONArray("SPS");
} else {
num++;
}
}
if (num == jsonArray.size()) {
// switch (cell.getCellType()) {
// case STRING:
jsonObject.put("DDH",ddh);
// break;
// case NUMERIC:
// jsonObject.put("DDH", cell.getNumericCellValue());
// break;
// default:
// jsonObject.put("DDH", "");
// }
//// jsonObject.put("DDH", cell.getStringCellValue());
}
}
switch (cell.getColumnIndex()) {
case 3:
if (!isddh) {
switch (cell.getCellType()) {
case STRING:
jsonObject.put("GMFMC", cell.getStringCellValue());
break;
case NUMERIC:
jsonObject.put("GMFMC", cell.getNumericCellValue());
break;
default:
jsonObject.put("GMFMC", "");
}
}
break;
case 4:
if (!isddh) {
switch (cell.getCellType()) {
case STRING:
jsonObject.put("GMFNSRSBH", cell.getStringCellValue());
break;
case NUMERIC:
jsonObject.put("GMFNSRSBH", cell.getNumericCellValue());
break;
default:
jsonObject.put("GMFNSRSBH", "");
}
}
break;
case 5:
if (!isddh) {
switch (cell.getCellType()) {
case STRING:
jsonObject.put("GMFYX", cell.getStringCellValue());
break;
case NUMERIC:
jsonObject.put("GMFYX", cell.getNumericCellValue());
break;
default:
jsonObject.put("GMFYX", "");
}
}
break;
case 6:
if (!isddh) {
switch (cell.getCellType()) {
case STRING:
jsonObject.put("GMFSJ", cell.getStringCellValue());
break;
case NUMERIC:
jsonObject.put("GMFSJ", cell.getNumericCellValue());
break;
default:
jsonObject.put("GMFSJ", "");
}
}
break;
case 17:
if (!isddh) {
switch (cell.getCellType()) {
case STRING:
jsonObject.put("BZ", cell.getStringCellValue());
break;
case NUMERIC:
jsonObject.put("BZ", cell.getNumericCellValue());
break;
default:
jsonObject.put("BZ", "");
}
}
break;
case 2:
switch (cell.getCellType()) {
case STRING:
SP.put("FXHXZ", cell.getStringCellValue());
break;
case NUMERIC:
SP.put("FXHXZ", cell.getNumericCellValue());
break;
default:
SP.put("FXHXZ", "");
}
break;
case 7:
switch (cell.getCellType()) {
case STRING:
SP.put("XMMC", cell.getStringCellValue());
break;
case NUMERIC:
SP.put("XMMC", cell.getNumericCellValue());
break;
default:
SP.put("XMMC", "");
}
break;
case 8:
switch (cell.getCellType()) {
case STRING:
SP.put("SPBM", cell.getStringCellValue());
break;
case NUMERIC:
SP.put("SPBM", cell.getNumericCellValue());
break;
default:
SP.put("SPBM", "");
}
break;
case 9:
switch (cell.getCellType()) {
case STRING:
SP.put("GGXH", cell.getStringCellValue());
break;
case NUMERIC:
SP.put("GGXH", cell.getNumericCellValue());
break;
default:
SP.put("GGXH", "");
}
break;
case 10:
switch (cell.getCellType()) {
case STRING:
SP.put("DW", cell.getStringCellValue());
break;
case NUMERIC:
SP.put("DW", cell.getNumericCellValue());
break;
default:
SP.put("DW", "");
}
break;
case 11:
switch (cell.getCellType()) {
case STRING:
SP.put("NUM", cell.getStringCellValue());
break;
case NUMERIC:
SP.put("NUM", cell.getNumericCellValue());
break;
default:
SP.put("NUM", "");
}
break;
case 12:
switch (cell.getCellType()) {
case STRING:
SP.put("SPDJ", cell.getStringCellValue());
break;
case NUMERIC:
SP.put("SPDJ", cell.getNumericCellValue());
break;
default:
SP.put("SPDJ", "");
}
break;
case 13:
switch (cell.getCellType()) {
case STRING:
SP.put("JE", cell.getStringCellValue());
break;
case NUMERIC:
SP.put("JE", cell.getNumericCellValue());
break;
default:
SP.put("JE", "");
}
break;
case 14:
switch (cell.getCellType()) {
case STRING:
SP.put("SL", cell.getStringCellValue());
break;
case NUMERIC:
SP.put("SL", cell.getNumericCellValue());
break;
default:
SP.put("SL", "");
}
break;
case 15:
switch (cell.getCellType()) {
case STRING:
SP.put("ZKJE", cell.getStringCellValue());
break;
case NUMERIC:
SP.put("ZKJE", cell.getNumericCellValue());
break;
default:
SP.put("ZKJE", "");
}
break;
case 16:
switch (cell.getCellType()) {
case STRING:
SP.put("YHZCBS", cell.getStringCellValue());
break;
case NUMERIC:
SP.put("YHZCBS", cell.getNumericCellValue());
break;
default:
SP.put("YHZCBS", "");
}
break;
}
}
if(StringUtil.isEmpty(jsonObject.getString("DDH"))){
continue row;
}
SPS.add(SP);
jsonObject.put("SPS", SPS);
if (num == jsonArray.size()) {
jsonArray.add(jsonObject);
} else {
jsonArray.set(bj, jsonObject);
}
}
// 关闭工作簿
workbook.close();
file.close();
return jsonArray;
}
public JSONArray getFileContent(long fileId) throws IOException {
System.out.println("获取参数附件ID"+fileId);
// 附件路径
String path = SystemEnvironment.getApplicationFolder()+"/hxinvoiceFile/"+fileId+"/";
System.out.println("文件下载路径"+path);
List<Long> fileUrls = getAttachmentManager().getBySubReference(fileId);
Attachment attachment = getAttachmentManager().getAttachmentByFileURL(fileUrls.get(0));
String filePath = path+attachment.getFilename();
JSONArray jsonArray = getFileContent(filePath);
return jsonArray;
}
public static String uploadContractToOA(Object[] fileInfos, String formId, String loginName, String updateAccountName) throws Exception {
OrgManager orgManager = (OrgManager) AppContext.getBean("orgManager");
V3xOrgMember member = orgManager.getMemberByLoginName(loginName);
V3xOrgAccount account = orgManager.getAccountByName(updateAccountName);
String refId = String.valueOf(Math.abs(UUID.randomUUID().getLeastSignificantBits()));
List<Attachment> attachments = new ArrayList<>();
File tempDir = new File(TEMP_DIR);
if (!tempDir.exists()) {
tempDir.mkdirs();
}
for (Object fileInfo : fileInfos) {
Map<String, Object> fileInfoMap = (Map<String, Object>) fileInfo;
String fileName = (String) fileInfoMap.get("fileName");
String url = (String) fileInfoMap.get("downloadUrl");
String savePath = TEMP_DIR + File.separator + fileName;
HttpClient.httpDownloadFile(url, null,savePath,"ITF-8");
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
FileUploadExporter fileUpload = new FileUploadExporter();
File file = new File(savePath);
if (file.exists() && file.length() <= MAX_FILE_SIZE) {
String uploadedPath = fileUpload.processUpload(new String[]{file.getAbsolutePath()});
Map<String, String> attachMeta = new HashMap<>();
attachMeta.put("type", "0");
attachMeta.put("fileUrl", uploadedPath);
attachMeta.put("size", String.valueOf(file.length()));
attachMeta.put("subReference", refId);
attachMeta.put("category", CATEGORY_CODE);
attachMeta.put("createdate", sdf.format(new Date()));
attachMeta.put("filename", fileName);
attachMeta.put("reference", formId);
attachMeta.put("mimeType", "application/" + "pdf");
attachments.add(new Attachment(attachMeta));
file.delete();
}
}
if (attachments.isEmpty()) return null;
AttachmentManager attachmentManager = (AttachmentManager) AppContext.getBean("attachmentManager");
attachmentManager.create(attachments, member.getId(), account.getId());
return refId;
}
private static boolean isBlank(String str) {
return str == null || str.trim().isEmpty();
}
}

View File

@@ -0,0 +1,27 @@
package com.seeyon.apps.esign.utils;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
public class HmacSHA256Util {
public static String encrypt(String data, String key)
throws NoSuchAlgorithmException, InvalidKeyException {
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(
key.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
sha256_HMAC.init(secret_key);
byte[] hash = sha256_HMAC.doFinal(data.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(hash);
}
public static void main(String[] args) throws Exception {
String data = "Hello World";
String key = "secret";
String result = encrypt(data, key);
System.out.println("HmacSHA256加密结果: " + result);
}
}

View File

@@ -0,0 +1,499 @@
package com.seeyon.apps.esign.utils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.stream.Collectors;
/**
* @ClassName: HttpClient
* @Description: HTTP请求工具类
* @Author: GiikJc
* @Date: 2022/7/12 15:03
*/
/**
* 发送Get请求HttpResponse httpGet(String url,Map<String,String> headers,String encode)
*发送Post请求同表单Post提交HttpResponse httpPostForm(String url,Map<String,String> params, Map<String,String> headers,String encode)
*发送Post Raw请求HttpResponse httpPostRaw(String url,String stringJson,Map<String,String> headers, String encode)
*发送Put Raw请求HttpResponse httpPutRaw(String url,String stringJson,Map<String,String> headers, String encode)
*发送Delete请求HttpResponse httpDelete(String url,Map<String,String> headers,String encode)
*/
public class HttpClient {
/**
* 发送 HTTP GET 请求下载文件
* @param url 下载文件的 URL
* @param headers 请求头
* @param savePath 文件保存的路径
* @param encode 文件内容的编码
* @return 下载成功返回 true失败返回 false
*/
public static boolean httpDownloadFile(String url, Map<String, String> headers, String savePath, String encode) {
if (encode == null) {
encode = "utf-8"; // 默认字符编码
}
CloseableHttpClient httpClient = null;
CloseableHttpResponse httpResponse = null;
InputStream inputStream = null;
OutputStream outputStream = null;
try {
// 创建 HttpClient 实例
httpClient = HttpClients.createDefault();
HttpGet httpGet = new HttpGet(url);
// 设置请求头
if (headers != null && headers.size() > 0) {
for (Map.Entry<String, String> entry : headers.entrySet()) {
httpGet.setHeader(entry.getKey(), entry.getValue());
}
}
// 执行请求
httpResponse = httpClient.execute(httpGet);
HttpEntity entity = httpResponse.getEntity();
// 检查响应状态码
if (httpResponse.getStatusLine().getStatusCode() == 200) {
inputStream = entity.getContent();
// 创建输出流,将文件保存到本地
outputStream = new FileOutputStream(savePath);
// 设置缓冲区
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
// 文件下载成功
return true;
} else {
System.out.println("Download failed, HTTP error code: " + httpResponse.getStatusLine().getStatusCode());
return false;
}
} catch (Exception e) {
e.printStackTrace();
return false;
} finally {
try {
if (inputStream != null) {
inputStream.close();
}
if (outputStream != null) {
outputStream.close();
}
if (httpResponse != null) {
httpResponse.close();
}
if (httpClient != null) {
httpClient.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 对queryString参数按key进行字典序升序排序
* @param queryString 原始参数字符串,如"b=2&a=1&c=3"
* @return 排序后的字符串,如"a=1&b=2&c=3"
*/
public static String sortQueryString(String queryString) {
if (queryString == null || queryString.isEmpty()) {
return queryString;
}
String[] pairs = queryString.split("&");
Map<String, String> params = new TreeMap<>();
for (String pair : pairs) {
String[] kv = pair.split("=");
if (kv.length == 2) {
params.put(kv[0], kv[1]);
} else if (kv.length == 1) {
params.put(kv[0], "");
}
}
return params.entrySet().stream()
.map(entry -> entry.getKey() + "=" + entry.getValue())
.collect(Collectors.joining("&"));
}
/**
* 发送http get请求
*/
public static String httpGet(String url,Map<String,String> headers,String encode){
if(encode == null){
encode = "utf-8";
}
CloseableHttpResponse httpResponse = null;
CloseableHttpClient closeableHttpClient = null;
String content = null;
//since 4.3 不再使用 DefaultHttpClient
try {
closeableHttpClient = HttpClientBuilder.create().build();
HttpGet httpGet = new HttpGet(url);
//设置header
if (headers != null && headers.size() > 0) {
for (Map.Entry<String, String> entry : headers.entrySet()) {
httpGet.setHeader(entry.getKey(),entry.getValue());
}
}
httpResponse = closeableHttpClient.execute(httpGet);
HttpEntity entity = httpResponse.getEntity();
content = EntityUtils.toString(entity, encode);
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
httpResponse.close();
} catch (IOException e) {
e.printStackTrace();
}
}
try { //关闭连接、释放资源
closeableHttpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
return content;
}
/**
* 发送 http post 请求参数以form表单键值对的形式提交。
*/
public static String httpPostForm(String url,Map<String,String> params, Map<String,String> headers,String encode){
if(encode == null){
encode = "utf-8";
}
String content = null;
CloseableHttpResponse httpResponse = null;
CloseableHttpClient closeableHttpClient = null;
try {
closeableHttpClient = HttpClients.createDefault();
HttpPost httpost = new HttpPost(url);
//设置header
if (headers != null && headers.size() > 0) {
for (Map.Entry<String, String> entry : headers.entrySet()) {
httpost.setHeader(entry.getKey(),entry.getValue());
}
}
//组织请求参数
List<NameValuePair> paramList = new ArrayList <NameValuePair>();
if(params != null && params.size() > 0){
Set<String> keySet = params.keySet();
for(String key : keySet) {
paramList.add(new BasicNameValuePair(key, params.get(key)));
}
}
httpost.setEntity(new UrlEncodedFormEntity(paramList, encode));
httpResponse = closeableHttpClient.execute(httpost);
HttpEntity entity = httpResponse.getEntity();
content = EntityUtils.toString(entity, encode);
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
httpResponse.close();
} catch (IOException e) {
e.printStackTrace();
}
}
try { //关闭连接、释放资源
closeableHttpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
return content;
}
/**
* 发送 http post 请求,参数以原生字符串进行提交
* @param url
* @param encode
* @return
*/
public static String httpPostRaw(String url,String stringJson,Map<String,String> headers, String encode){
if(encode == null){
encode = "utf-8";
}
String content = null;
CloseableHttpResponse httpResponse = null;
CloseableHttpClient closeableHttpClient = null;
try {
//HttpClients.createDefault()等价于 HttpClientBuilder.create().build();
closeableHttpClient = HttpClients.createDefault();
HttpPost httpost = new HttpPost(url);
//设置header
httpost.setHeader("Content-type", "application/json");
if (headers != null && headers.size() > 0) {
for (Map.Entry<String, String> entry : headers.entrySet()) {
httpost.setHeader(entry.getKey(),entry.getValue());
}
}
//组织请求参数
StringEntity stringEntity = new StringEntity(stringJson, encode);
httpost.setEntity(stringEntity);
//响应信息
httpResponse = closeableHttpClient.execute(httpost);
HttpEntity entity = httpResponse.getEntity();
content = EntityUtils.toString(entity, encode);
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
httpResponse.close();
} catch (IOException e) {
e.printStackTrace();
}
}
try { //关闭连接、释放资源
closeableHttpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
return content;
}
/**
* 发送 http put 请求,参数以原生字符串进行提交
* @param url
* @param encode
* @return
*/
public static String httpPutRaw(String url,String stringJson,Map<String,String> headers, String encode){
if(encode == null){
encode = "utf-8";
}
CloseableHttpResponse httpResponse = null;
CloseableHttpClient closeableHttpClient = null;
String content = null;
//since 4.3 不再使用 DefaultHttpClient
try {
//HttpClients.createDefault()等价于 HttpClientBuilder.create().build();
closeableHttpClient = HttpClients.createDefault();
HttpPut httpput = new HttpPut(url);
//设置header
httpput.setHeader("Content-type", "application/json");
if (headers != null && headers.size() > 0) {
for (Map.Entry<String, String> entry : headers.entrySet()) {
httpput.setHeader(entry.getKey(),entry.getValue());
}
}
//组织请求参数
StringEntity stringEntity = new StringEntity(stringJson, encode);
httpput.setEntity(stringEntity);
//响应信息
httpResponse = closeableHttpClient.execute(httpput);
HttpEntity entity = httpResponse.getEntity();
content = EntityUtils.toString(entity, encode);
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
httpResponse.close();
} catch (IOException e) {
e.printStackTrace();
}
}
try {
closeableHttpClient.close(); //关闭连接、释放资源
} catch (IOException e) {
e.printStackTrace();
}
return content;
}
/**
* 发送http delete请求
*/
public static String httpDelete(String url,Map<String,String> headers,String encode){
if(encode == null){
encode = "utf-8";
}
String content = null;
CloseableHttpResponse httpResponse = null;
CloseableHttpClient closeableHttpClient = null;
try {
//since 4.3 不再使用 DefaultHttpClient
closeableHttpClient = HttpClientBuilder.create().build();
HttpDelete httpdelete = new HttpDelete(url);
//设置header
if (headers != null && headers.size() > 0) {
for (Map.Entry<String, String> entry : headers.entrySet()) {
httpdelete.setHeader(entry.getKey(),entry.getValue());
}
}
httpResponse = closeableHttpClient.execute(httpdelete);
HttpEntity entity = httpResponse.getEntity();
content = EntityUtils.toString(entity, encode);
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
httpResponse.close();
} catch (IOException e) {
e.printStackTrace();
}
}
try { //关闭连接、释放资源
closeableHttpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
return content;
}
/**
* 发送 http post 请求,支持文件上传
*/
public static String httpPostFormMultipart(String url,Map<String,String> params, List<File> files,Map<String,String> headers,String encode){
if(encode == null){
encode = "utf-8";
}
CloseableHttpResponse httpResponse = null;
CloseableHttpClient closeableHttpClient = null;
String content = null;
//since 4.3 不再使用 DefaultHttpClient
try {
closeableHttpClient = HttpClients.createDefault();
HttpPost httpost = new HttpPost(url);
//设置header
if (headers != null && headers.size() > 0) {
for (Map.Entry<String, String> entry : headers.entrySet()) {
httpost.setHeader(entry.getKey(),entry.getValue());
}
}
MultipartEntityBuilder mEntityBuilder = MultipartEntityBuilder.create();
mEntityBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
mEntityBuilder.setCharset(Charset.forName(encode));
// 普通参数
ContentType contentType = ContentType.create("text/plain",Charset.forName(encode));//解决中文乱码
if (params != null && params.size() > 0) {
Set<String> keySet = params.keySet();
for (String key : keySet) {
mEntityBuilder.addTextBody(key, params.get(key),contentType);
}
}
//二进制参数
if (files != null && files.size() > 0) {
for (File file : files) {
mEntityBuilder.addBinaryBody("file", file);
}
}
httpost.setEntity(mEntityBuilder.build());
httpResponse = closeableHttpClient.execute(httpost);
HttpEntity entity = httpResponse.getEntity();
content = EntityUtils.toString(entity, encode);
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
httpResponse.close();
} catch (IOException e) {
e.printStackTrace();
}
}
try { //关闭连接、释放资源
closeableHttpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
return content;
}
public static String uploadBinaryFile(String url, Map<String,String> headers,
InputStream io, String fileName) throws IOException {
CloseableHttpClient client = HttpClients.createDefault();
HttpPut put = new HttpPut(url);
String responseBody = null;
try {
// 设置请求头
for (String key : headers.keySet()) {
put.addHeader(key, headers.get(key));
}
// 构建多部分实体
MultipartEntityBuilder builder = MultipartEntityBuilder.create()
.setMode(HttpMultipartMode.BROWSER_COMPATIBLE)
.setCharset(Charset.forName("UTF-8"));
builder.addBinaryBody("file", io, ContentType.MULTIPART_FORM_DATA, fileName);
put.setEntity(builder.build());
// 执行请求
CloseableHttpResponse response = null;
try {
response = client.execute(put);
HttpEntity resEntity = response.getEntity();
responseBody = EntityUtils.toString(resEntity, "UTF-8");
// 无论状态码如何,都返回响应体
return responseBody;
} finally {
if(response != null) {
response.close();
}
}
} finally {
client.close();
io.close();
}
}
}

View File

@@ -0,0 +1,28 @@
package com.seeyon.apps.esign.utils;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.util.Iterator;
import java.util.Map;
public class JsonCleaner {
public static String removeEmptyObjects(String jsonStr) throws Exception {
ObjectMapper mapper = new ObjectMapper();
ObjectNode node = (ObjectNode) mapper.readTree(jsonStr);
Iterator<Map.Entry<String, JsonNode>> fields = node.fields();
while (fields.hasNext()) {
Map.Entry<String, com.fasterxml.jackson.databind.JsonNode> entry = fields.next();
if (entry.getValue().isObject() && entry.getValue().isEmpty()) {
fields.remove();
}
}
return mapper.writeValueAsString(node);
}
}

View File

@@ -0,0 +1,84 @@
package com.seeyon.apps.esign.utils;
import com.alibaba.fastjson.JSONObject;
import com.seeyon.aicloud.common.JsonUtils;
import com.seeyon.apps.esign.config.EsignConfigProvider;
import com.seeyon.apps.esign.constants.EsignConfigConstants;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicHeader;
import org.apache.http.util.EntityUtils;
import www.seeyon.com.utils.StringUtil;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Map;
public class ProtUtil {
private static final Log log = LogFactory.getLog(ProtUtil.class);
private EsignConfigProvider configProvider = EsignConfigProvider.getInstance();
/**
* 获取一个token
*
* @return
* @throws IOException
* @throws FileNotFoundException
*/
private String getToken(String oatokenurl,String restName,String restPassword,String loginName) throws FileNotFoundException, IOException {
String address = oatokenurl + restName + "/" + restPassword;
if(StringUtil.isNotEmpty(loginName)){
address = address +"?loginName="+loginName;
}
DefaultHttpClient client = new DefaultHttpClient();
String result = "";
HttpGet get = new HttpGet(address);
// 添加 Headers 信息
get.addHeader(new BasicHeader("Accept", "application/json"));
try {
HttpResponse res = client.execute(get);
if (res.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
result = EntityUtils.toString(res.getEntity());
}
} catch (Exception e) {
throw new RuntimeException(e);
}
String token = "";
if(result.contains("{")) {
JSONObject jsObj = JSONObject.parseObject(result);
token = jsObj.get("id").toString();
}else {
token = result;
}
return token;
}
/**
* 调用post接口
* @return
*/
public String sendPostNotification(String params, String urlParam, String token) throws IOException {
String host = configProvider.getBizConfigByKey(EsignConfigConstants.OA_HOST);
String tokenGetUrl = configProvider.getBizConfigByKey(EsignConfigConstants.getTokenUrl);
String restName = configProvider.getBizConfigByKey(EsignConfigConstants.restName);
String restPwd = configProvider.getBizConfigByKey(EsignConfigConstants.restPwd);
String oatoken = getToken(host + tokenGetUrl,restName,restPwd,null);
String url = host + urlParam+ token+"?token="+oatoken;
log.info("调用恢复超级节点接口请求地址为: " + url);
String respStr = HttpClient.httpPostRaw(url, params, null, null);
log.info("调用恢复超级节点接口响应结果: " + respStr);
if(!"1".equals(respStr)) {
Map map = JsonUtils.parseObject(respStr, Map.class);
throw new RuntimeException("恢复阻塞的超级节点失败: " + map.get("message"));
}
return respStr;
}
}

View File

@@ -0,0 +1,33 @@
package com.seeyon.ctp.rest.resources.esign;
import cn.hutool.log.Log;
import com.seeyon.apps.esign.service.EsignFlowQueryService;
import com.seeyon.ctp.common.AppContext;
import com.seeyon.ctp.rest.resources.BaseResource;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
@Path("/eFlow")
public class EsignFlowQueryResource extends BaseResource {
private static final Log log = Log.get(EsignFlowQueryResource.class);
private EsignFlowQueryService esignFlowQueryService = (EsignFlowQueryService) AppContext.getBean("esignFlowQueryService");
@Context
HttpServletRequest req;
@GET
@Produces({"application/json"})
@Path("/queryFlowStatus")
public Response queryTemplates() {
try {
return success(esignFlowQueryService.queryFlow(req.getParameter("eFlowId")));
}catch (Exception e) {
log.error(e.getMessage(),e);
}
return fail("失败");
}
}

View File

@@ -0,0 +1,50 @@
package com.seeyon.ctp.rest.resources.esign;
import cn.hutool.log.Log;
import com.seeyon.apps.esign.service.EsignFileTemplateService;
import com.seeyon.ctp.common.AppContext;
import com.seeyon.ctp.rest.resources.BaseResource;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
import java.util.Map;
@Path("/etemplate")
public class EsignTemplateResource extends BaseResource {
private static final Log log = Log.get(EsignTemplateResource.class);
private EsignFileTemplateService esignFileTemplateService = (EsignFileTemplateService) AppContext.getBean("esignFileTemplateService");
@GET
@Produces({"application/json"})
@Consumes({"application/json"})
@Path("/querypage")
public Response queryTemplates(@QueryParam("pageNum") Integer pageNum) {
try {
Map<String, Object> map = esignFileTemplateService.queryTemplates(pageNum);
return success(map);
}catch (Exception e) {
log.error(e.getMessage(),e);
}
return fail("失败");
}
@POST
@Produces({"application/json"})
@Consumes({"application/json"})
@Path("/compareurl")
public Response compare(@QueryParam("templateRefId") String templateRefId,@QueryParam("contractRefId") String contractRefId) {
try {
String compareDetailUrl = esignFileTemplateService.getCompareDetailUrl(templateRefId, contractRefId);
return success(compareDetailUrl);
}catch (Exception e) {
log.error(e.getMessage(),e);
}
return fail("失败");
}
}

View File

@@ -0,0 +1,9 @@
package java;
import com.seeyon.apps.esign.EsignPluginApi;
public class TestOne {
public static void main(String[] args) {
new EsignPluginApi();
}
}