Commit 509f7f09 by 邓实川 Committed by chenzg

优化一哈e签宝,添加合同使用记录和余量更新,增加e签宝回调接口记录

parent 48024304
/**
* <p>Title: DzhtSignflowFinish.java</p>
* <p>Description: </p>
* @author dsc
* @date 2020年5月20日
* @version 1.0
*/
package cn.timer.api.bean.dzht;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* <p>
* Title: DzhtSignflowFinish.java
* </p>
* <p>
* Description:
* </p>
*
* @author dsc
* @date 2020年5月20日
* @version 1.0
*/
@Entity
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "dzht_signflow_finish")
@ApiModel("e签宝流程结束回调")
public class DzhtSignflowFinish extends Model<DzhtSignflowFinish>{
private static final long serialVersionUID = 7207935929987536355L;
@Id
@GeneratedValue
@TableId(type = IdType.AUTO)
@ApiModelProperty(value = "编号")
private Integer id;
@ApiModelProperty(value = "标记该通知的业务类型,该通知固定为:SIGN_FLOW_FINISH")
private String action;
@ApiModelProperty(value = "流程id")
private String flowId;
@ApiModelProperty(value = "签署文件主题描述")
private String businessScence;
@ApiModelProperty(value = "可能存在的任务状态: 2-完成,所有签署人完成签署 3-撤销,发起方撤销签署任务 5-过期(签署截止日到期后触发)7-拒签")
private String flowStatus;
@ApiModelProperty(value = "签署任务发起时间 格式yyyy-MM-dd HH:mm:ss")
private String createTime;
@ApiModelProperty(value = "签署任务结束时间 格式yyyy-MM-dd HH:mm:ss")
private String endTime;
@ApiModelProperty(value = "当流程异常结束时,附加终止原因描述")
private String statusDescription;
@ApiModelProperty(value = "时间戳")
private Long timestamp;
}
......@@ -88,6 +88,9 @@ public class QyzxUseRecord extends Model<QyzxUseRecord> {
@ApiModelProperty(value = "创建人 ", example = "")
private String createUser;
@ApiModelProperty(value = "使用人手机号 ", example = "")
@ApiModelProperty(value = "使用人手机号(短信) ", example = "")
private String userPhone;
@ApiModelProperty(value = "流程id(合同) ", example = "")
private String flowId;
}
/**
* <p>Title: EsignCallBackController.java</p>
* <p>Description: </p>
* @author dsc
* @date 2020年5月19日
* @version 1.0
*/
package cn.timer.api.callback.esign;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.transaction.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import cn.timer.api.callback.esign.service.SafeVerify;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
/**
* <p>
* Title: EsignCallBackController.java
* </p>
* <p>
* Description:
* </p>
*
* @author dsc
* @date 2020年5月19日
* @version 1.0
*/
@RestController
@Transactional
@Api(tags = "99.97 e签宝回调接口")
@RequestMapping(value = "/callback/esign", produces = { "application/json" })
public class EsignCallBackController {
@Autowired
private HttpServletRequest request;
// @Autowired
// private HttpServletResponse response;
private static final String appSecret = "7b100813cca2746081c57837855ac5af";
@PostMapping(value = "/dev") // TODO
@ApiOperation(value = "合同流程结束通知(dev)", httpMethod = "POST", notes = "接口发布说明")
public Integer wxcallback_test() {
String res = null;
SafeVerify sv = new SafeVerify();
try {
res = sv.checkPass(request, appSecret);
// response.setCharacterEncoding("UTF-8");
// response.getWriter().append("Served at: ").append(request.getContextPath()).append("\n")
// .append("是否通过验证:----》").append(res);
} catch (IOException e) {
e.printStackTrace();
}
if (res != null && res.equals("true"))
return 200; // 返回响应码
return 500;
}
}
package cn.timer.api.callback.esign.service;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Base64.Encoder;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
/***
*
* @Description: 摘要加密算法辅助类
* @Team: 公有云技术支持小组
* @Author: 天云小生
* @Date: 2018年01月14日
*/
public class DigestHelper {
/***
* 获取请求签名值
*
* @param data
* 加密前数据
* @param key
* 密钥
* @param algorithm
* HmacMD5 HmacSHA1 HmacSHA256 HmacSHA384 HmacSHA512
* @param encoding
* 编码格式
* @return HMAC加密后16进制字符串
* @throws Exception
*/
public static String getSignature(String data, String key, String algorithm, String encoding) {
Mac mac = null;
try {
mac = Mac.getInstance(algorithm);
SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(encoding), algorithm);
mac.init(secretKey);
mac.update(data.getBytes(encoding));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
System.out.println("获取Signature签名信息异常:" + e.getMessage());
return null;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
System.out.println("获取Signature签名信息异常:" + e.getMessage());
return null;
} catch (InvalidKeyException e) {
e.printStackTrace();
System.out.println("获取Signature签名信息异常:" + e.getMessage());
return null;
}
return byte2hex(mac.doFinal());
}
/***
* 计算文件的Content-MD5
*
* @param filePath
* @return
*/
public static String getContentMD5(String filePath) {
Encoder encoder = Base64.getEncoder();
// 获取文件MD5的二进制数组(128位)
byte[] bytes = getFileMD5Bytes128(filePath);
// 对文件MD5的二进制数组进行base64编码(而不是对32位的16进制字符串进行编码)
return encoder.encodeToString(bytes);
}
/***
* 获取文件MD5-二进制数组(128位)
*
* @param filePath
* @return
* @throws IOException
*/
public static byte[] getFileMD5Bytes128(String filePath) {
FileInputStream fis = null;
byte[] md5Bytes = null;
try {
File file = new File(filePath);
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();
fis.close();
} catch (FileNotFoundException e) {
System.out.println(e.getMessage());
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
System.out.println(e.getMessage());
e.printStackTrace();
} catch (IOException e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
return md5Bytes;
}
/***
* 获取文件SHA256-十六进制字符串(原文SHA256摘要)
*
* @param filePath
* @return
* @throws IOException
*/
public static String getFileSHA256(String filePath) {
FileInputStream fis = null;
byte[] md5Bytes = null;
String hashSHA256 = null;
try {
File file = new File(filePath);
fis = new FileInputStream(file);
MessageDigest md5 = MessageDigest.getInstance("SHA-256");
byte[] buffer = new byte[1024];
int length = -1;
while ((length = fis.read(buffer, 0, 1024)) != -1) {
md5.update(buffer, 0, length);
}
md5Bytes = md5.digest();
fis.close();
hashSHA256 = byte2hex(md5Bytes);
} catch (FileNotFoundException e) {
e.printStackTrace();
System.out.println(e.getMessage());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
System.out.println(e.getMessage());
} catch (IOException e) {
e.printStackTrace();
System.out.println(e.getMessage());
}
return hashSHA256;
}
/***
* 获取字符串的SHA256-十六进制字符串
*
* @param str
* @return
* @throws IOException
*/
public static String getStringSHA256(String str) {
byte[] md5Bytes = null;
try {
md5Bytes = str.getBytes("UTF-8");
// 拿到一个SHA256转换器
MessageDigest messageDigest;
messageDigest = MessageDigest.getInstance("SHA-256");
// 输入的字符串转换成字节数组
byte[] inputByteArray = str.getBytes();
// inputByteArray是输入字符串转换得到的字节数组
messageDigest.update(inputByteArray);
// 转换并返回结果,也是字节数组,包含16个元素
md5Bytes = messageDigest.digest();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return byte2hex(md5Bytes);
}
/***
* 将byte[]转成16进制字符串
*
* @param data
*
* @return 16进制字符串
*/
public static String byte2hex(byte[] data) {
StringBuilder hash = new StringBuilder();
String stmp;
for (int n = 0; data != null && n < data.length; n++) {
stmp = Integer.toHexString(data[n] & 0XFF);
if (stmp.length() == 1)
hash.append('0');
hash.append(stmp);
}
return hash.toString();
}
}
/**
*
*/
package cn.timer.api.callback.esign.service;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.springframework.transaction.annotation.Transactional;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import cn.hutool.json.JSONObject;
import cn.timer.api.bean.dzht.DzhtSignflowFinish;
import cn.timer.api.bean.qyzx.businessService.QyzxUseRecord;
/**
* @author chen_xi 验证签名
*/
@Transactional
public class SafeVerify {
public static void main(String[] args) {
String rbody = "{\"action\":\"SIGN_FLOW_FINISH\",\"flowId\":\"1e49e34bdc5f4550a8fd6d7922c68101\",\"businessScence\":\"随便\",\"flowStatus\":\"2\",\"createTime\":\"2020-05-20 10:00:06\",\"endTime\":\"2020-05-20 10:01:06\",\"statusDescription\":\"完成\",\"timestamp\":1589940066939}";
String rbody2 = "{\"action\":\"SIGN_FLOW_UPDATE\",\"flowId\":\"1e49e34bdc5f4550a8fd6d7922c68101\",\"accountId\":\"1b6d7e255140443fa65287a6ff74149d\",\"authorizedAccountId\":\"1b6d7e255140443fa65287a6ff74149d\",\"order\":1,\"signTime\":\"2020-05-20 10:01:06\",\"signResult\":2,\"resultDescription\":\"签署完成\",\"timestamp\":1589940066702,\"thirdPartyUserId\":\"431003199610102831\"}";
JSONObject jsonBody = new JSONObject(rbody);
JSONObject jsonBody2 = new JSONObject(rbody2);
System.err.println(jsonBody.getStr("action"));
System.err.println(jsonBody2.getStr("action"));
}
public String checkPass(HttpServletRequest request, String appSecret) throws UnsupportedEncodingException {
String signture = request.getHeader("X-Tsign-Open-SIGNATURE");
// 1. 获取时间戳的字节流
String timestampHeader = request.getHeader("X-Tsign-Open-TIMESTAMP");
// String content_type =request
// 2. 获取query请求字符串
String requestQuery = getRequestQueryStr(request);
// 3. 获取body的数据
String rbody = getRequestBody(request, "UTF-8");
System.err.println("requestQuery:" + requestQuery);
System.err.println("rbody:" + rbody);
// 3.5 保存回调结果到数据库
JSONObject jsonBody = new JSONObject(rbody);
String action = jsonBody.getStr("action");
String flowId = jsonBody.getStr("flowId");
Long timestamp = jsonBody.getLong("timestamp");
if (action.equals("SIGN_FLOW_FINISH")) { // 签署人签署完成回调通知
String businessScence = jsonBody.getStr("businessScence");
String flowStatus = jsonBody.getStr("flowStatus");
String createTime = jsonBody.getStr("createTime");
String endTime = jsonBody.getStr("endTime");
String statusDescription = jsonBody.getStr("statusDescription");
DzhtSignflowFinish dzhtSignflowFinish = new DzhtSignflowFinish();
dzhtSignflowFinish.setAction(action);
dzhtSignflowFinish.setBusinessScence(businessScence);
dzhtSignflowFinish.setCreateTime(createTime);
dzhtSignflowFinish.setEndTime(endTime);
dzhtSignflowFinish.setFlowId(flowId);
dzhtSignflowFinish.setFlowStatus(flowStatus);
dzhtSignflowFinish.setStatusDescription(statusDescription);
dzhtSignflowFinish.setTimestamp(timestamp);
boolean result = dzhtSignflowFinish.insert();
String scene = null;
if (result) {
if (flowStatus == "2") {
scene = "完成";
} else if (flowStatus == "3") {
scene = "撤销";
} else if (flowStatus == "5") {
scene = "过期";
} else if (flowStatus == "7") {
scene = "拒签";
}
QyzxUseRecord.builder().scene(scene).build()
.update(new QueryWrapper<QyzxUseRecord>().lambda().eq(QyzxUseRecord::getFlowId, flowId));
}
} else if (action.equals("SIGN_FLOW_UPDATE")) { // 流程结束回调通知
// String accountId = jsonBody.getStr("accountId");
// String authorizedAccountId = jsonBody.getStr("authorizedAccountId");
// String order = jsonBody.getStr("order");
// String signTime = jsonBody.getStr("signTime");
// String signResult = jsonBody.getStr("signResult");
// String resultDescription = jsonBody.getStr("resultDescription");
// String thirdPartyUserId = jsonBody.getStr("thirdPartyUserId");
} else if (action.equals("SIGN_DOC_EXPIRE_REMIND")) { // 流程文件过期前提醒通知
} else if (action.equals("SIGN_DOC_EXPIRE")) { // 流程文件过期通知
}
// 4、按照规则进行加密
String signdata = timestampHeader + requestQuery + rbody;
String mySignature = DigestHelper.getSignature(signdata, appSecret, "HmacSHA256", "UTF-8");
System.out.println("加密出来的签名值:----------->>>>>>" + mySignature);
System.out.println("header里面的签名值:---------->>>>>>" + signture);
if (mySignature.equals(signture)) {
System.out.println("校验通过");
return "true";
} else {
System.out.println("校验失败");
return "false";
}
}
/**
* 获取请求body
*
* @param request
* @param encoding
* @return
*/
private String getRequestBody(HttpServletRequest request, String encoding) {
// 请求内容RequestBody
String reqBody = null;
int contentLength = request.getContentLength();
if (contentLength < 0) {
return null;
}
byte buffer[] = new byte[contentLength];
try {
for (int i = 0; i < contentLength;) {
int readlen = request.getInputStream().read(buffer, i, contentLength - i);
if (readlen == -1) {
break;
}
i += readlen;
}
} catch (IOException e) {
e.printStackTrace();
}
try {
reqBody = new String(buffer, encoding);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return reqBody;
}
/**
* 获取query请求字符串
*
* @param request
* @return
*/
private String getRequestQueryStr(HttpServletRequest request) {
// 对 Query 参数按照字典对 Key 进行排序后,按照value1+value2方法拼接
// 转换一下数据类型并排序
List<String> req_List = new ArrayList<String>();
Enumeration<String> reqEnu = request.getParameterNames();
while (reqEnu.hasMoreElements()) {
req_List.add(reqEnu.nextElement());
}
Collections.sort(req_List);
String requestQuery = "";
for (String key : req_List) {
String value = request.getParameter(key);
requestQuery += value == null ? "" : value;
}
System.out.println("获取的query请求字符串是:------》》》" + requestQuery);
return requestQuery;
}
}
......@@ -11,8 +11,6 @@ import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.timer.api.aspect.lang.bean.ValidationError;
import cn.timer.api.utils.Result;
import cn.timer.api.utils.ResultUtil;
......
......@@ -43,6 +43,7 @@ import cn.timer.api.bean.dzht.DzhtAssoQyzc;
import cn.timer.api.bean.dzht.DzhtAssoSdgzq;
import cn.timer.api.bean.dzht.DzhtAssoTpyz;
import cn.timer.api.bean.qyzx.businessService.QyzxRemainingQuantity;
import cn.timer.api.bean.qyzx.businessService.QyzxUseRecord;
import cn.timer.api.bean.yggl.YgglMainEmp;
import cn.timer.api.config.annotation.CurrentUser;
import cn.timer.api.config.annotation.UserBean;
......@@ -414,12 +415,13 @@ public class DzhtController2 {
}
// 创建签署流程
@Transactional
@PostMapping("/signflows")
@ApiOperation(value = "创建签署流程", httpMethod = "POST", notes = "接口发布说明")
public Result<Object> signflows(@CurrentUser UserBean userBean, @RequestBody DzhtAssoCjlc lc) {
Integer empNum = userBean.getEmpNum();
Integer orgCode = userBean.getOrgCode();
String flowId = null;
QyzxRemainingQuantity quantity = QyzxRemainingQuantity.builder().build().selectOne(
new LambdaQueryWrapper<QyzxRemainingQuantity>().eq(QyzxRemainingQuantity::getOrgCode, orgCode)
.eq(QyzxRemainingQuantity::getPmid, 2).gt(QyzxRemainingQuantity::getRemainder, 0));
......@@ -476,8 +478,9 @@ public class DzhtController2 {
try {
TokenHelper.getTokenData();// 获取鉴权
jsonObject = SignHelper.createSignFlow(sfs);
lc.setFlowId(jsonObject.getString("flowId"));
lc.setCreater(userBean.getEmpNum());
flowId = jsonObject.getString("flowId");
lc.setFlowId(flowId);
lc.setCreater(empNum);
lc.setCreatedTime(new Date());
lc.setOrgCode(orgCode);
lc.insert();
......@@ -485,6 +488,28 @@ public class DzhtController2 {
e1.printStackTrace();
return ResultUtil.error();
}
QyzxUseRecord qyzxUseRecord = new QyzxUseRecord();
qyzxUseRecord.setCreateTime(new Date());
YgglMainEmp ygglMainEmp = YgglMainEmp.builder().build().selectOne(new QueryWrapper<YgglMainEmp>().lambda()
.eq(YgglMainEmp::getEmpNum, empNum).select(YgglMainEmp::getName));
String name = null;
if (ygglMainEmp != null) {
name = ygglMainEmp.getName();
}
qyzxUseRecord.setCreateUser(name);
qyzxUseRecord.setOriginalTotalNum(remainder);
qyzxUseRecord.setNowTotalNum(--remainder);
qyzxUseRecord.setOrderNo(quantity.getOrderNo());
qyzxUseRecord.setOrgCode(orgCode);
qyzxUseRecord.setUseNum(1);
qyzxUseRecord.setScene("签署中");
qyzxUseRecord.setFlowId(flowId);
qyzxUseRecord.insert();
quantity.setRemainder(remainder);
quantity.updateById();
return ResultUtil.data(jsonObject, "创建签署流程成功");
}
......@@ -893,10 +918,13 @@ public class DzhtController2 {
try {
TokenHelper.getTokenData();// 获取鉴权
SignHelper.rushSign(flowId, getID(userBean.getEmpNum()), noticeTypes, rushsignAccountId);
JSONObject json = SignHelper.rushSign(flowId, getID(userBean.getEmpNum()), noticeTypes, rushsignAccountId);
if (json != null && json.getLong("code") != 0) {
return ResultUtil.error(json.getString("message"));
}
} catch (DefineException e) {
// return ResultUtil.error("当前用户非流程发起人, 不能执行催签操作");
e.printStackTrace();
return ResultUtil.error("当前用户非流程发起人, 不能执行催签操作");
}
return ResultUtil.success();
}
......
......@@ -426,14 +426,16 @@ public class SignHelper {
* @param flowId 创建签署流程时返回的签署流程ID
* @throws DefineException
* @author 宫清
* @return
* @date 2019年7月21日 下午9:27:41
*/
public static void rushSign(String flowId, String accoundId, String noticeTypes, String rushsignAccountId)
public static JSONObject rushSign(String flowId, String accoundId, String noticeTypes, String rushsignAccountId)
throws DefineException {
String param = SignParamUtil.rushsignersParam(accoundId, noticeTypes, rushsignAccountId);
JSONObject json = HttpHelper.doCommHttp(RequestType.PUT, ConfigConstant.urgeSgin_URL(flowId), param);
JSONHelper.castDataJson(json, Object.class);
// JSONHelper.castDataJson(json, Object.class);
return json;
}
/**
......
package cn.timer.api.dao.dzht;
import org.springframework.stereotype.Repository;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import cn.timer.api.bean.dzht.DzhtSignflowFinish;
/**
* e签宝结束回调
*
* @author Administrator
*
*/
@Repository
public interface DzhtSignflowFinishMapper extends BaseMapper<DzhtSignflowFinish> {
}
\ No newline at end of file
......@@ -167,7 +167,7 @@ config-8timer:
expirationTime: 3153600000000L
expirationTime_pri: 600000L
esign: # e签宝
callbackUrl: 'http://192.168.4.13/callback/esign/dev'
callbackUrl: 'https://test-8timer-pc.youlingrc.com/callback/esign/dev'
redirectUrl: 'http://test-8timer-pc.youlingrc.com/#/ElecCon/index'
# host: https://smlopenapi.esign.cn
# test: https://smlopenapi.esign.cn
......
......@@ -141,6 +141,8 @@ config-8timer:
expirationTime: 3153600000000L
expirationTime_pri: 600000L
esign: # e签宝
callbackUrl: 'https://test-8timer-pc.youlingrc.com/callback/esign/dev'
redirectUrl: 'http://test-8timer-pc.youlingrc.com/#/ElecCon/index'
# host: https://openapi.esign.cn
# PROJECT_ID: 4438775940
# PROJECT_SECRET: 7b100813cca2746081c57837855ac5af
......
......@@ -141,6 +141,8 @@ config-8timer:
expirationTime: 3153600000000L
expirationTime_pri: 600000L
esign: # e签宝
callbackUrl: 'https://test-8timer-pc.youlingrc.com/callback/esign/dev'
redirectUrl: 'http://test-8timer-pc.youlingrc.com/#/ElecCon/index'
# host: https://smlopenapi.esign.cn
# PROJECT_ID: 4438775940
# PROJECT_SECRET: 7b100813cca2746081c57837855ac5af
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment