对接云南省局医保
This commit is contained in:
@@ -3,4 +3,6 @@ echo off
|
|||||||
:: 添加jar包到本地仓库
|
:: 添加jar包到本地仓库
|
||||||
cmd /k "mvn install:install-file -Dfile=jacob-1.21.jar -DgroupId=com.jacob -DartifactId=jacob -Dversion=1.21 -Dpackaging=jar"
|
cmd /k "mvn install:install-file -Dfile=jacob-1.21.jar -DgroupId=com.jacob -DartifactId=jacob -Dversion=1.21 -Dpackaging=jar"
|
||||||
|
|
||||||
|
:: cmd /k "mvn install:install-file -Dfile=hsaf-common-1.0.0-SNAPSHOT.jar -DgroupId=hsaf.common -DartifactId=hsaf -Dversion=1.0.0-SNAPSHOT -Dpackaging=jar"
|
||||||
|
|
||||||
pause
|
pause
|
||||||
|
|||||||
BIN
doc/lib/hsaf-common-1.0.0-SNAPSHOT.jar
Normal file
BIN
doc/lib/hsaf-common-1.0.0-SNAPSHOT.jar
Normal file
Binary file not shown.
7
pom.xml
7
pom.xml
@@ -179,6 +179,13 @@
|
|||||||
<artifactId>itext-asian</artifactId>
|
<artifactId>itext-asian</artifactId>
|
||||||
<version>5.2.0</version>
|
<version>5.2.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!--<dependency>
|
||||||
|
<groupId>hsaf.common</groupId>
|
||||||
|
<artifactId>hsaf</artifactId>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
</dependency>-->
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ public class YnChsConfig {
|
|||||||
private String url;
|
private String url;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 医保机构编码
|
* 两定医保机构编码
|
||||||
*/
|
*/
|
||||||
private String fixmeDinsCode;
|
private String fixmeDinsCode;
|
||||||
/**
|
/**
|
||||||
@@ -43,5 +43,30 @@ public class YnChsConfig {
|
|||||||
*/
|
*/
|
||||||
private String cityCode;
|
private String cityCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用ID
|
||||||
|
*/
|
||||||
|
private String appid;
|
||||||
|
/**
|
||||||
|
* 应用密钥
|
||||||
|
*/
|
||||||
|
private String appKey;
|
||||||
|
/**
|
||||||
|
* 应用名称
|
||||||
|
*/
|
||||||
|
private String appName;
|
||||||
|
/**
|
||||||
|
* 渠道私钥
|
||||||
|
*/
|
||||||
|
private String channelPrivateKey;
|
||||||
|
/**
|
||||||
|
* 渠道公钥
|
||||||
|
*/
|
||||||
|
private String channelPublicKey;
|
||||||
|
/**
|
||||||
|
* 平台公钥
|
||||||
|
*/
|
||||||
|
private String platformPublicKey;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ public interface CharsetConst {
|
|||||||
|
|
||||||
// 中文编码
|
// 中文编码
|
||||||
String GB2312 = "GB2312";
|
String GB2312 = "GB2312";
|
||||||
|
// UTF8
|
||||||
|
String UTF8 = "UTF-8";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,17 +29,16 @@ public class HispayController {
|
|||||||
|
|
||||||
private final IHispayService hispayService;
|
private final IHispayService hispayService;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过医保卡或医保电子凭证读卡
|
* 通过医保卡或医保电子凭证读卡
|
||||||
*
|
*
|
||||||
* @return com.dpkj.common.vo.Result<?>
|
* @return com.dpkj.common.vo.Result<?>
|
||||||
* @author 萧道子 2025/5/20
|
* @author 萧道子 2025/5/20
|
||||||
*/
|
*/
|
||||||
@PostMapping("findReadCode")
|
@PostMapping("getUserInfoByChsCode")
|
||||||
public Result<?> findReadCode() {
|
public Result<?> getUserInfoByChsCode() {
|
||||||
try {
|
try {
|
||||||
JSONObject res = hispayService.readCode();
|
JSONObject res = hispayService.getUserInfoByChsCode();
|
||||||
return Result.ok("成功", res);
|
return Result.ok("成功", res);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@@ -56,15 +55,15 @@ public class HispayController {
|
|||||||
* @return com.dpkj.common.vo.Result<?>
|
* @return com.dpkj.common.vo.Result<?>
|
||||||
* @author 萧道子 2025/5/28
|
* @author 萧道子 2025/5/28
|
||||||
*/
|
*/
|
||||||
@PostMapping("findReadCard")
|
@PostMapping("getUserInfoByChsCard")
|
||||||
public Result<?> findReadCard(@RequestBody JSONObject data) {
|
public Result<?> getUserInfoByChsCard(@RequestBody JSONObject data) {
|
||||||
try {
|
try {
|
||||||
String password = data.getString("password");
|
String password = data.getString("password");
|
||||||
if (StrUtil.isEmpty(password)) {
|
if (StrUtil.isEmpty(password)) {
|
||||||
throw new RuntimeException("密码不可为空");
|
throw new RuntimeException("密码不可为空");
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONObject res = hispayService.readCard(password);
|
JSONObject res = hispayService.getUserInfoByChsCard(password);
|
||||||
return Result.ok("成功", res);
|
return Result.ok("成功", res);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
|||||||
@@ -8,21 +8,20 @@ import com.dpkj.modules.chs.hischs.vo.OutpatientFinalModel;
|
|||||||
public interface IHispayService {
|
public interface IHispayService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过医保电子凭证读卡
|
* 通过医保电子凭证获-取患者身份信息
|
||||||
*
|
*
|
||||||
* @return com.alibaba.fastjson.JSONObject
|
* @return com.alibaba.fastjson.JSONObject
|
||||||
* @author 萧道子 2025/5/28
|
* @author 萧道子 2025/5/28
|
||||||
*/
|
*/
|
||||||
JSONObject readCode();
|
JSONObject getUserInfoByChsCode();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过医保卡-读卡
|
* 通过医保卡-取患者身份信息
|
||||||
*
|
*
|
||||||
* @return com.alibaba.fastjson.JSONObject
|
* @return com.alibaba.fastjson.JSONObject
|
||||||
* @author 萧道子 2025/5/28
|
* @author 萧道子 2025/5/28
|
||||||
*/
|
*/
|
||||||
JSONObject readCard(String password);
|
JSONObject getUserInfoByChsCard(String password);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import com.jacob.com.Dispatch;
|
|||||||
import com.jacob.com.Variant;
|
import com.jacob.com.Variant;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.w3c.dom.Document;
|
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -69,6 +68,150 @@ public class HispayServiceImpl implements IHispayService {
|
|||||||
// ComThread.Release(); //容易导致线程发生阻塞
|
// ComThread.Release(); //容易导致线程发生阻塞
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject getUserInfoByChsCode() {
|
||||||
|
/** 1、组装参数 */
|
||||||
|
JSONObject params = new JSONObject()
|
||||||
|
.fluentPut("cardtype", "9") // 1.就诊卡,2.医保卡,5.门诊号,6.患者姓名和电话号码,8.电子健康码/卡,9.医保电子凭证
|
||||||
|
.fluentPut("cardno", "") // 患者就诊卡号
|
||||||
|
.fluentPut("sfzh", "") // 身份证号
|
||||||
|
.fluentPut("hzxm", "") // 患者姓名
|
||||||
|
.fluentPut("phone", ""); // 患者电话号码
|
||||||
|
String paramsXml = this.handleParams(params);
|
||||||
|
|
||||||
|
/** 2、调用COM函数 */
|
||||||
|
log.debug("[HispayServiceImpl][readCode][医保读卡-电子凭证] 接口入参:{}", paramsXml);
|
||||||
|
Variant vres = new Variant("", true);
|
||||||
|
Variant call = Dispatch.call(dispatch, "fRun", "BMZXX010", paramsXml, vres);
|
||||||
|
String resStr = vres.getStringRef();
|
||||||
|
log.debug("[HispayServiceImpl][readCode][医保读卡-电子凭证] call返回值:{} 结果:{}", call, resStr);
|
||||||
|
|
||||||
|
|
||||||
|
/** 3、处理读卡结果 */
|
||||||
|
JSONObject result = verifyResult(resStr);
|
||||||
|
if (!result.containsKey("item")) {
|
||||||
|
throw new RuntimeException("item数据为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.getJSONObject("item");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject getUserInfoByChsCard(String password) {
|
||||||
|
/** 1、组装参数 */
|
||||||
|
JSONObject params = new JSONObject()
|
||||||
|
.fluentPut("cardtype", "2") // 1.就诊卡,2.医保卡,5.门诊号,6.患者姓名和电话号码,8.电子健康码/卡,9.医保电子凭证
|
||||||
|
.fluentPut("cardno", "") // 患者就诊卡号
|
||||||
|
.fluentPut("sfzh", "") // 身份证号
|
||||||
|
.fluentPut("hzxm", "") // 患者姓名
|
||||||
|
.fluentPut("phone", ""); // 患者电话号码
|
||||||
|
String paramsXml = this.handleParams(params, password);
|
||||||
|
|
||||||
|
/** 2、调用COM函数 */
|
||||||
|
log.debug("[HispayServiceImpl][readCard][医保读卡-医保卡] 接口入参:{}", paramsXml);
|
||||||
|
Variant vres = new Variant("", true);
|
||||||
|
Variant call = Dispatch.call(dispatch, "fRun", "BMZXX010", paramsXml, vres);
|
||||||
|
String resStr = vres.getStringRef();
|
||||||
|
log.debug("[HispayServiceImpl][readCard][医保读卡-医保卡] call返回值:{} 结果:{}", call, resStr);
|
||||||
|
|
||||||
|
/** 3、处理读卡结果 */
|
||||||
|
JSONObject result = this.verifyResult(resStr);
|
||||||
|
if (!result.containsKey("item")) {
|
||||||
|
throw new RuntimeException("item数据为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.getJSONObject("item");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResultData chsCodeAsOutpatientBegin(OutpatientBeginModel data) {
|
||||||
|
// 用户读卡-生成token
|
||||||
|
JSONObject userInfo = this.getUserInfoByChsCode();
|
||||||
|
String patientId = userInfo.getString("patid");
|
||||||
|
data.setPatientId(patientId);
|
||||||
|
|
||||||
|
// 更新常量状态 已读卡
|
||||||
|
ChsPayStateConst.put(data.getPrescriptionNo(), 1);
|
||||||
|
|
||||||
|
return this.outpatientBudget(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResultData chsCodeAsOutpatientFinal(OutpatientFinalModel data) {
|
||||||
|
/** 1、组装参数 */
|
||||||
|
String requestTime = DateUtil.now();
|
||||||
|
data.setPaytime(requestTime);
|
||||||
|
JSONObject params = ((JSONObject) JSON.toJSON(data))
|
||||||
|
.fluentPut("czksfbz", "0") // 是否扣院内账户,与预算保持一致
|
||||||
|
.fluentPut("zfjsbz", "0") // 是否自费结算,与预算保持一致,0根据病人医保代码结算,1自费结算
|
||||||
|
.fluentPut("ybrc", "")
|
||||||
|
.fluentPut("ptlsh", "")
|
||||||
|
.fluentPut("jysm", "");
|
||||||
|
String paramsXml = this.handleParams(params);
|
||||||
|
|
||||||
|
/** 2、调用COM函数 */
|
||||||
|
log.debug("[HispayServiceImpl][chsCodeAsOutpatientFinal][门诊缴费-结算] 接口入参:{}", paramsXml);
|
||||||
|
Variant resVariant = new Variant("", true);
|
||||||
|
Variant call = Dispatch.call(dispatch, "fRun", "BMZJF002", paramsXml, resVariant);
|
||||||
|
String resStr = resVariant.getStringRef();
|
||||||
|
log.debug("[HispayServiceImpl][chsCodeAsOutpatientFinal][门诊缴费-结算] call返回值:{} 结果:{}", call, resStr);
|
||||||
|
String responseTime = DateUtil.now();
|
||||||
|
|
||||||
|
/** 3、处理结果 */
|
||||||
|
JSONObject result = verifyResult(resStr);
|
||||||
|
|
||||||
|
return new ResultData()
|
||||||
|
.setRequestTime(requestTime)
|
||||||
|
.setRequestContent(paramsXml)
|
||||||
|
.setResponseTime(responseTime)
|
||||||
|
.setPatientId(data.getPatid())
|
||||||
|
.setResponseContent(resStr)
|
||||||
|
.setResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 医保预结算
|
||||||
|
*
|
||||||
|
* @param data :
|
||||||
|
* @return com.dpkj.common.vo.ResultData
|
||||||
|
* @author 萧道子 2025/10/25
|
||||||
|
*/
|
||||||
|
private ResultData outpatientBudget(OutpatientBeginModel data) {
|
||||||
|
/** 1、组装参数 */
|
||||||
|
JSONObject params = new JSONObject()
|
||||||
|
.fluentPut("patid", data.getPatientId()) // 病人ID
|
||||||
|
.fluentPut("cfxhhj", data.getPrescriptionNo()) // 划价单据,格式:单据1,单据2,单据3
|
||||||
|
.fluentPut("czksfbz", "0") // 是否扣院内账户,0不使用院内账户,1使用院内账户(默认不使用院内账户)
|
||||||
|
.fluentPut("zfjsbz", "0") // 是否自费结算,0根据医保代码缴费,1自费结算(默认自费结算)
|
||||||
|
.fluentPut("ybrc", ""); // 医保入参,xml节点
|
||||||
|
String paramsXml = this.handleParams(params);
|
||||||
|
|
||||||
|
String requestTime = DateUtil.now();
|
||||||
|
|
||||||
|
/** 2、调用COM函数 */
|
||||||
|
log.debug("[HispayServiceImpl][outpatientBudget][门诊缴费-预算] 接口入参:{}", paramsXml);
|
||||||
|
Variant resVariant = new Variant("", true);
|
||||||
|
Variant call = Dispatch.call(dispatch, "fRun", "BMZJF001", paramsXml, resVariant);
|
||||||
|
String resStr = resVariant.getStringRef();
|
||||||
|
log.debug("[HispayServiceImpl][outpatientBudget][门诊缴费-预算] call返回值:{} 结果:{}", call, resStr);
|
||||||
|
|
||||||
|
String responseTime = DateUtil.now();
|
||||||
|
|
||||||
|
/** 3、处理结果 */
|
||||||
|
JSONObject result = verifyResult(resStr);
|
||||||
|
|
||||||
|
return new ResultData()
|
||||||
|
.setRequestTime(requestTime)
|
||||||
|
.setRequestContent(paramsXml)
|
||||||
|
.setResponseTime(responseTime)
|
||||||
|
.setPatientId(data.getPatientId())
|
||||||
|
.setResponseContent(resStr)
|
||||||
|
.setResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理参数
|
* 处理参数
|
||||||
*
|
*
|
||||||
@@ -77,7 +220,7 @@ public class HispayServiceImpl implements IHispayService {
|
|||||||
* @return java.lang.String
|
* @return java.lang.String
|
||||||
* @author 萧道子 2025/5/27
|
* @author 萧道子 2025/5/27
|
||||||
*/
|
*/
|
||||||
private String processParameters(JSONObject params, String password) {
|
private String handleParams(JSONObject params, String password) {
|
||||||
JSONObject req = new JSONObject() {{
|
JSONObject req = new JSONObject() {{
|
||||||
put("timestamp", ""); // 请求发送时间 DateUtil.format(DateUtil.date(), "yyyyMMddHHmmss")
|
put("timestamp", ""); // 请求发送时间 DateUtil.format(DateUtil.date(), "yyyyMMddHHmmss")
|
||||||
put("requestid", ""); // 唯一请求id IDGenerator.getSnowflakeIdToStr()
|
put("requestid", ""); // 唯一请求id IDGenerator.getSnowflakeIdToStr()
|
||||||
@@ -85,8 +228,11 @@ public class HispayServiceImpl implements IHispayService {
|
|||||||
put("password", password); // 密码
|
put("password", password); // 密码
|
||||||
put("params", params);
|
put("params", params);
|
||||||
}};
|
}};
|
||||||
Document document = XmlUtil.mapToXml(req, "request");
|
return this.JsonObjectToXml(req);
|
||||||
return XmlUtil.toStr(document, "UTF-8", false, true);
|
}
|
||||||
|
|
||||||
|
private String handleParams(JSONObject params) {
|
||||||
|
return handleParams(params, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -98,7 +244,6 @@ public class HispayServiceImpl implements IHispayService {
|
|||||||
* @author 萧道子 2025/5/28
|
* @author 萧道子 2025/5/28
|
||||||
*/
|
*/
|
||||||
private JSONObject verifyResult(String resStr) {
|
private JSONObject verifyResult(String resStr) {
|
||||||
|
|
||||||
if (StrUtil.isBlank(resStr)) {
|
if (StrUtil.isBlank(resStr)) {
|
||||||
throw new RuntimeException("信息获取失败");
|
throw new RuntimeException("信息获取失败");
|
||||||
}
|
}
|
||||||
@@ -119,149 +264,15 @@ public class HispayServiceImpl implements IHispayService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public JSONObject readCode() {
|
* 将jsonobject转为xml
|
||||||
/** 1、组装参数 */
|
*
|
||||||
JSONObject val = new JSONObject()
|
* @param val :
|
||||||
.fluentPut("cardtype", "9") // 1.就诊卡,2.医保卡,5.门诊号,6.患者姓名和电话号码,8.电子健康码/卡,9.医保电子凭证
|
* @return java.lang.String
|
||||||
.fluentPut("cardno", "") // 患者就诊卡号
|
* @author 萧道子 2025/10/25
|
||||||
.fluentPut("sfzh", "") // 身份证号
|
*/
|
||||||
.fluentPut("hzxm", "") // 患者姓名
|
private String JsonObjectToXml(JSONObject val) {
|
||||||
.fluentPut("phone", ""); // 患者电话号码
|
return XmlUtil.toStr(XmlUtil.mapToXml(val, "request"), "UTF-8", false, true);
|
||||||
String params = processParameters(val, null);
|
|
||||||
log.debug("[HispayServiceImpl][readCode][医保读卡-电子凭证] 接口入参:{}", params);
|
|
||||||
|
|
||||||
/** 2、调用COM函数 */
|
|
||||||
Variant vres = new Variant("", true);
|
|
||||||
Variant call = Dispatch.call(dispatch, "fRun", "BMZXX010", params, vres);
|
|
||||||
|
|
||||||
String resStr = vres.getStringRef();
|
|
||||||
log.debug("[HispayServiceImpl][readCode][医保读卡-电子凭证] call返回值:{} 结果:{}", call, resStr);
|
|
||||||
|
|
||||||
|
|
||||||
/** 3、处理读卡结果 */
|
|
||||||
JSONObject result = verifyResult(resStr);
|
|
||||||
if (!result.containsKey("item")) {
|
|
||||||
throw new RuntimeException("item数据为空");
|
|
||||||
}
|
|
||||||
|
|
||||||
return result.getJSONObject("item");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public JSONObject readCard(String password) {
|
|
||||||
|
|
||||||
/** 1、组装参数 */
|
|
||||||
JSONObject val = new JSONObject()
|
|
||||||
.fluentPut("cardtype", "2") // 1.就诊卡,2.医保卡,5.门诊号,6.患者姓名和电话号码,8.电子健康码/卡,9.医保电子凭证
|
|
||||||
.fluentPut("cardno", "") // 患者就诊卡号
|
|
||||||
.fluentPut("sfzh", "") // 身份证号
|
|
||||||
.fluentPut("hzxm", "") // 患者姓名
|
|
||||||
.fluentPut("phone", ""); // 患者电话号码
|
|
||||||
String params = processParameters(val, password);
|
|
||||||
log.debug("[HispayServiceImpl][readCard][医保读卡-医保卡] 接口入参:{}", params);
|
|
||||||
|
|
||||||
/** 2、调用COM函数 */
|
|
||||||
Variant vres = new Variant("", true);
|
|
||||||
Variant call = Dispatch.call(dispatch, "fRun", "BMZXX010", params, vres);
|
|
||||||
|
|
||||||
String resStr = vres.getStringRef();
|
|
||||||
log.debug("[HispayServiceImpl][readCard][医保读卡-医保卡] call返回值:{} 结果:{}", call, resStr);
|
|
||||||
|
|
||||||
/** 3、处理读卡结果 */
|
|
||||||
JSONObject result = verifyResult(resStr);
|
|
||||||
if (!result.containsKey("item")) {
|
|
||||||
throw new RuntimeException("item数据为空");
|
|
||||||
}
|
|
||||||
|
|
||||||
return result.getJSONObject("item");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private ResultData outpatientBudget(OutpatientBeginModel data) {
|
|
||||||
|
|
||||||
/** 1、组装参数 */
|
|
||||||
JSONObject val = new JSONObject()
|
|
||||||
.fluentPut("patid", data.getPatientId()) // 病人ID
|
|
||||||
.fluentPut("cfxhhj", data.getPrescriptionNo()) // 划价单据,格式:单据1,单据2,单据3
|
|
||||||
.fluentPut("czksfbz", "0") // 是否扣院内账户,0不使用院内账户,1使用院内账户(默认不使用院内账户)
|
|
||||||
.fluentPut("zfjsbz", "0") // 是否自费结算,0根据医保代码缴费,1自费结算(默认自费结算)
|
|
||||||
.fluentPut("ybrc", ""); // 医保入参,xml节点
|
|
||||||
String params = processParameters(val, data.getPassword());
|
|
||||||
log.debug("[HispayServiceImpl][outpatientBudget][门诊缴费-预算] 接口入参:{}", params);
|
|
||||||
|
|
||||||
String requestTime = DateUtil.now();
|
|
||||||
|
|
||||||
/** 2、调用COM函数 */
|
|
||||||
Variant resVariant = new Variant("", true);
|
|
||||||
Variant call = Dispatch.call(dispatch, "fRun", "BMZJF001", params, resVariant);
|
|
||||||
|
|
||||||
String responseTime = DateUtil.now();
|
|
||||||
String resStr = resVariant.getStringRef();
|
|
||||||
log.debug("[HispayServiceImpl][outpatientBudget][门诊缴费-预算] call返回值:{} 结果:{}", call, resStr);
|
|
||||||
|
|
||||||
|
|
||||||
/** 3、处理结果 */
|
|
||||||
JSONObject result = verifyResult(resStr);
|
|
||||||
|
|
||||||
return new ResultData()
|
|
||||||
.setRequestTime(requestTime)
|
|
||||||
.setRequestContent(params)
|
|
||||||
.setResponseTime(responseTime)
|
|
||||||
.setPatientId(data.getPatientId())
|
|
||||||
.setResponseContent(resStr)
|
|
||||||
.setResult(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ResultData chsCodeAsOutpatientBegin(OutpatientBeginModel data) {
|
|
||||||
// 用户读卡-生成token
|
|
||||||
JSONObject userInfo = readCode();
|
|
||||||
String patientId = userInfo.getString("patid");
|
|
||||||
data.setPatientId(patientId);
|
|
||||||
|
|
||||||
// 更新常量状态 已读卡
|
|
||||||
ChsPayStateConst.put(data.getPrescriptionNo(), 1);
|
|
||||||
|
|
||||||
return outpatientBudget(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ResultData chsCodeAsOutpatientFinal(OutpatientFinalModel data) {
|
|
||||||
|
|
||||||
/** 1、组装参数 */
|
|
||||||
String requestTime = DateUtil.now();
|
|
||||||
data.setPaytime(requestTime);
|
|
||||||
JSONObject val = ((JSONObject) JSON.toJSON(data))
|
|
||||||
.fluentPut("czksfbz", "0") // 是否扣院内账户,与预算保持一致
|
|
||||||
.fluentPut("zfjsbz", "0") // 是否自费结算,与预算保持一致,0根据病人医保代码结算,1自费结算
|
|
||||||
.fluentPut("ybrc", "")
|
|
||||||
.fluentPut("ptlsh", "")
|
|
||||||
.fluentPut("jysm", "");
|
|
||||||
String params = processParameters(val, null);
|
|
||||||
log.debug("[HispayServiceImpl][chsCodeAsOutpatientFinal][门诊缴费-结算] 接口入参:{}", params);
|
|
||||||
|
|
||||||
/** 2、调用COM函数 */
|
|
||||||
Variant resVariant = new Variant("", true);
|
|
||||||
Variant call = Dispatch.call(dispatch, "fRun", "BMZJF002", params, resVariant);
|
|
||||||
|
|
||||||
String responseTime = DateUtil.now();
|
|
||||||
String resStr = resVariant.getStringRef();
|
|
||||||
log.debug("[HispayServiceImpl][chsCodeAsOutpatientFinal][门诊缴费-结算] call返回值:{} 结果:{}", call, resStr);
|
|
||||||
|
|
||||||
/** 3、处理结果 */
|
|
||||||
JSONObject result = verifyResult(resStr);
|
|
||||||
|
|
||||||
return new ResultData()
|
|
||||||
.setRequestTime(requestTime)
|
|
||||||
.setRequestContent(params)
|
|
||||||
.setResponseTime(responseTime)
|
|
||||||
.setPatientId(data.getPatid())
|
|
||||||
.setResponseContent(resStr)
|
|
||||||
.setResult(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package com.dpkj.modules.chs.ynchs.constant;
|
||||||
|
|
||||||
|
public interface YnchsConst {
|
||||||
|
|
||||||
|
String URL_BASE = "/eapdomain/callService";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 人员信息获取
|
||||||
|
*/
|
||||||
|
String URL_1101 = URL_BASE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 身份认证
|
||||||
|
*/
|
||||||
|
String URL_1191 = URL_BASE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移动支付-费用明细上传
|
||||||
|
*/
|
||||||
|
String URL_6201 = "/org/local/api/hos/uldFeeInfo";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移动支付-支付下单
|
||||||
|
*/
|
||||||
|
String URL_6202 = "/org/local/api/hos/pay_order";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移动支付-医保退费
|
||||||
|
*/
|
||||||
|
String URL_6203 = "/org/local/api/hos/refund_Order";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移动支付-医保订单信息同步
|
||||||
|
*/
|
||||||
|
String URL_6204 = URL_BASE;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
package com.dpkj.modules.chs.ynchs.controller;
|
package com.dpkj.modules.chs.ynchs.controller;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
|
||||||
import com.dpkj.common.vo.Result;
|
import com.dpkj.common.vo.Result;
|
||||||
import com.dpkj.modules.chs.ynchs.service.IYnChsPayService;
|
import com.dpkj.modules.chs.padchs.response.ChsCheckResponse;
|
||||||
|
import com.dpkj.modules.chs.ynchs.service.IYnchspayByDllService;
|
||||||
|
import com.dpkj.modules.chs.ynchs.service.IYnchspayByWebapiService;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@@ -20,18 +21,21 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
@RequestMapping("/chs/yn")
|
@RequestMapping("/chs/yn")
|
||||||
public class YnChsPayController {
|
public class YnChsPayController {
|
||||||
|
|
||||||
private final IYnChsPayService ynChsPayService;
|
private final IYnchspayByWebapiService ynchspayByWebapiService;
|
||||||
|
|
||||||
|
private final IYnchspayByDllService ynchspayByDllService;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取支付凭证
|
* 刷脸获取身份信息
|
||||||
*
|
*
|
||||||
* @return com.dpkj.common.vo.Result<?>
|
* @return com.dpkj.common.vo.Result<?>
|
||||||
* @author 萧道子 2025/10/22
|
* @author 萧道子 2025/10/24
|
||||||
*/
|
*/
|
||||||
@PostMapping("getPayToken")
|
@PostMapping("getUserByFace")
|
||||||
public Result<?> getPayToken() {
|
public Result<?> getUserByFace() {
|
||||||
try {
|
try {
|
||||||
JSONObject result = ynChsPayService.getPayToken();
|
ChsCheckResponse result = ynchspayByDllService.getUserByFace();
|
||||||
return Result.ok("成功", result);
|
return Result.ok("成功", result);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return Result.error(e.getMessage());
|
return Result.error(e.getMessage());
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package com.dpkj.modules.chs.ynchs.dll;
|
|||||||
|
|
||||||
import com.sun.jna.Library;
|
import com.sun.jna.Library;
|
||||||
import com.sun.jna.Native;
|
import com.sun.jna.Native;
|
||||||
import com.sun.jna.Pointer;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -21,8 +20,8 @@ public class YnChsPayDll {
|
|||||||
*/
|
*/
|
||||||
public static EcDll instance() throws DllRegistrationException {
|
public static EcDll instance() throws DllRegistrationException {
|
||||||
try {
|
try {
|
||||||
// return Native.load("CHSInterfaceYn.dll", EcDll.class);
|
return Native.load("CHSInterfaceYn.dll", EcDll.class);
|
||||||
return Native.load("D:\\Code\\CHS\\CHSInterfaceYn.dll", EcDll.class);
|
// return Native.load("D:\\Code\\CHS\\CHSInterfaceYn.dll", EcDll.class);
|
||||||
} catch (UnsatisfiedLinkError e) {
|
} catch (UnsatisfiedLinkError e) {
|
||||||
log.info("[YnChsPayDll][instance][云南省级医保动态库] SDK注册失败:{}", e.getMessage());
|
log.info("[YnChsPayDll][instance][云南省级医保动态库] SDK注册失败:{}", e.getMessage());
|
||||||
throw new DllRegistrationException("Failed to load YnChsPayDll library: ", e);
|
throw new DllRegistrationException("Failed to load YnChsPayDll library: ", e);
|
||||||
@@ -62,7 +61,7 @@ public class YnChsPayDll {
|
|||||||
* @return int
|
* @return int
|
||||||
* @author 萧道子 2025/10/22
|
* @author 萧道子 2025/10/22
|
||||||
*/
|
*/
|
||||||
int Init(String fixmeDinsCode, String infoSysCode, String infoSysSign, String url, Pointer errMsg);
|
int Init(String fixmeDinsCode, String infoSysCode, String infoSysSign, String url, Object errMsg);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -78,7 +77,7 @@ public class YnChsPayDll {
|
|||||||
* @return int
|
* @return int
|
||||||
* @author 萧道子 2025/10/22
|
* @author 萧道子 2025/10/22
|
||||||
*/
|
*/
|
||||||
int BusinessHandle(String fixmeDinsCode, String infoSysCode, String infoSysSign, String inputData, Pointer outputData, Pointer errMsg);
|
int BusinessHandle(String fixmeDinsCode, String infoSysCode, String infoSysSign, String inputData, Object outputData, Object errMsg);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -94,7 +93,7 @@ public class YnChsPayDll {
|
|||||||
* @return int
|
* @return int
|
||||||
* @author 萧道子 2025/10/22
|
* @author 萧道子 2025/10/22
|
||||||
*/
|
*/
|
||||||
int BusinessHandleW(String fixmeDinsCode, String infoSysCode, String infoSysSign, String inputData, Pointer outputData, Pointer errMsg);
|
int BusinessHandleW(String fixmeDinsCode, String infoSysCode, String infoSysSign, String inputData, Object outputData, Object errMsg);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
package com.dpkj.modules.chs.ynchs.service;
|
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Auther: 萧道子
|
|
||||||
* @Date: 2025/8/7 14:45
|
|
||||||
* @Description:
|
|
||||||
*/
|
|
||||||
public interface IYnChsPayService {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 下单
|
|
||||||
*
|
|
||||||
* @param val :
|
|
||||||
* @return void
|
|
||||||
* @author 萧道子 2025/10/22
|
|
||||||
*/
|
|
||||||
JSONObject placeOrderByApi(String val);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 下单
|
|
||||||
*
|
|
||||||
* @param val :
|
|
||||||
* @return void
|
|
||||||
* @author 萧道子 2025/10/22
|
|
||||||
*/
|
|
||||||
JSONObject getPayToken();
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package com.dpkj.modules.chs.ynchs.service;
|
||||||
|
|
||||||
|
import com.dpkj.modules.chs.padchs.response.ChsCheckResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Auther: 萧道子
|
||||||
|
* @Date: 2025/8/7 14:45
|
||||||
|
* @Description:
|
||||||
|
*/
|
||||||
|
public interface IYnchspayByDllService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过扫脸获取用户信息
|
||||||
|
*
|
||||||
|
* @return com.dpkj.modules.chs.padchs.response.ChsCheckResponse
|
||||||
|
* @author 萧道子 2025/10/24
|
||||||
|
*/
|
||||||
|
ChsCheckResponse getUserByFace();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.dpkj.modules.chs.ynchs.service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Auther: 萧道子
|
||||||
|
* @Date: 2025/8/7 14:45
|
||||||
|
* @Description:
|
||||||
|
*/
|
||||||
|
public interface IYnchspayByWebapiService {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,185 +0,0 @@
|
|||||||
package com.dpkj.modules.chs.ynchs.service.impl;
|
|
||||||
|
|
||||||
import cn.hutool.core.date.DatePattern;
|
|
||||||
import cn.hutool.core.date.DateTime;
|
|
||||||
import cn.hutool.core.date.DateUtil;
|
|
||||||
import cn.hutool.core.util.RandomUtil;
|
|
||||||
import cn.hutool.crypto.SecureUtil;
|
|
||||||
import cn.hutool.http.HttpRequest;
|
|
||||||
import cn.hutool.http.HttpResponse;
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
|
||||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
|
||||||
import com.dpkj.common.config.YnChsConfig;
|
|
||||||
import com.dpkj.common.constant.CharsetConst;
|
|
||||||
import com.dpkj.common.utils.IDGenerator;
|
|
||||||
import com.dpkj.modules.chs.padchs.response.ChsCheckResponse;
|
|
||||||
import com.dpkj.modules.chs.padchs.service.IPadChsPayService;
|
|
||||||
import com.dpkj.modules.chs.ynchs.dll.YnChsPayDll;
|
|
||||||
import com.dpkj.modules.chs.ynchs.service.IYnChsPayService;
|
|
||||||
import com.sun.jna.Memory;
|
|
||||||
import com.sun.jna.Pointer;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Auther: 萧道子
|
|
||||||
* @Date: 2025/8/7 14:46
|
|
||||||
* @Description:
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@Service
|
|
||||||
public class YnChsPayServiceImpl implements IYnChsPayService {
|
|
||||||
|
|
||||||
private YnChsPayDll.EcDll dll;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private YnChsConfig ynChsConfig;
|
|
||||||
@Autowired
|
|
||||||
private IPadChsPayService padChsPayService;
|
|
||||||
|
|
||||||
@PostConstruct
|
|
||||||
public void postConstruct() {
|
|
||||||
log.info("[YnChsPayServiceImpl][postConstruct][云南省局医保DLL] 初始化动态链接库");
|
|
||||||
try {
|
|
||||||
dll = YnChsPayDll.instance();
|
|
||||||
} catch (YnChsPayDll.DllRegistrationException e) {
|
|
||||||
log.error("[YnChsPayServiceImpl][postConstruct][云南省局医保DLL] 加载失败:{}", e.getMessage());
|
|
||||||
throw new RuntimeException("云南省局医保DLL库加载失败:" + e.getMessage(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JSONObject placeOrderByApi(String val) {
|
|
||||||
String nonce = IDGenerator.getSnowflakeIdToStr();
|
|
||||||
DateTime date = DateUtil.date();
|
|
||||||
String timestamp = DateUtil.format(date, DatePattern.PURE_DATETIME_PATTERN);
|
|
||||||
String infoSysSign = ynChsConfig.getInfoSysSign();
|
|
||||||
String signature = SecureUtil.sha256(timestamp + infoSysSign + nonce);
|
|
||||||
|
|
||||||
String fixmeDinsCode = ynChsConfig.getFixmeDinsCode();
|
|
||||||
String cityCode = ynChsConfig.getCityCode();
|
|
||||||
String fixmeDinsName = ynChsConfig.getFixmeDinsName();
|
|
||||||
String msgid = fixmeDinsCode + timestamp + RandomUtil.randomNumbers(4);
|
|
||||||
|
|
||||||
JSONObject inputData = new JSONObject().fluentPut("data", new JSONObject().fluentPut("mdtrt_cert_type", "02")
|
|
||||||
.fluentPut("mdtrt_cert_no", "02")
|
|
||||||
.fluentPut("card_sn", "")
|
|
||||||
.fluentPut("begntime", "")
|
|
||||||
.fluentPut("psn_cert_type", "01")
|
|
||||||
.fluentPut("certno", "530111199701031117")
|
|
||||||
.fluentPut("psn_name", "薛家俊"));
|
|
||||||
JSONObject params = new JSONObject()
|
|
||||||
.fluentPut("infno", "1101") // 交易编号
|
|
||||||
.fluentPut("msgid", msgid) // 发送方报文ID 定点医药机构编号(12)+时间(14)+顺序号(4) 时间格式:yyyyMMddHHmmss
|
|
||||||
.fluentPut("mdtrtarea_admvs", cityCode) // 就医地医保区划
|
|
||||||
.fluentPut("insuplc_admdvs", "") // 参保地医保区划
|
|
||||||
.fluentPut("recer_sys_code", "yinyitong") // 接收方系统代码
|
|
||||||
.fluentPut("dev_no", "") // 设备编号
|
|
||||||
.fluentPut("dev_safe_info", "") // 设备安全信息
|
|
||||||
.fluentPut("cainfo", "") // 数字签名信息
|
|
||||||
.fluentPut("signtype", "") // 签名类型
|
|
||||||
.fluentPut("infver", "V1.0") // 接口版本号
|
|
||||||
.fluentPut("opter_type", 3) // 经办人类别 1-经办人;2-自助终端;3-移动终端
|
|
||||||
.fluentPut("opter", "test") // 经办人
|
|
||||||
.fluentPut("opter_name", "test") // 经办人姓名
|
|
||||||
.fluentPut("inf_time", DateUtil.format(date, DatePattern.NORM_DATETIME_PATTERN)) // 交易时间
|
|
||||||
.fluentPut("fixmedins_code", fixmeDinsCode) // 定点医药机构编号
|
|
||||||
.fluentPut("fixmedins_name", fixmeDinsName) // 定点医药机构名称
|
|
||||||
.fluentPut("sign_no", nonce) // 交易签到流水号
|
|
||||||
.fluentPut("input", inputData); // 交易输入
|
|
||||||
|
|
||||||
String paramsStr = params.toString(SerializerFeature.WriteNullStringAsEmpty);
|
|
||||||
log.debug("[LOG9823][placeOrder][云南省局医保-API][获取支付授权] 请求入参: {}", paramsStr);
|
|
||||||
// 请求
|
|
||||||
HttpResponse response = HttpRequest.post(ynChsConfig.getUrl())
|
|
||||||
.header("Content-Type", "application/json")
|
|
||||||
.header("fixmedins_code", fixmeDinsCode) // 医保机构编码
|
|
||||||
.header("infosyscode", ynChsConfig.getInfoSysCode()) // 服务商统一社会信用代码
|
|
||||||
.header("hsf_nonce", nonce) // 校验码 非重复的随机字符串(十分钟内不能重复)
|
|
||||||
.header("hsf_timestamp", timestamp) // 当前时间戳(秒)
|
|
||||||
.header("hsf_signature", signature) // 加密生成的签名
|
|
||||||
.body(paramsStr)
|
|
||||||
.execute();
|
|
||||||
try {
|
|
||||||
String resultBody = response.body();
|
|
||||||
log.debug("[LOG9823][placeOrder][云南省局医保-API][获取支付授权] 请求出参: {}", resultBody);
|
|
||||||
// 释放资源
|
|
||||||
response.close();
|
|
||||||
|
|
||||||
JSONObject result = JSONObject.parseObject(resultBody);
|
|
||||||
|
|
||||||
// TODO 萧道子 2025/10/22 : 判断逻辑
|
|
||||||
|
|
||||||
return result;
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("[LOG3760][placeOrder][云南省局医保-API][获取支付授权] 请求报错 ERR:{}", e.getMessage());
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JSONObject getPayToken() {
|
|
||||||
// 初始化
|
|
||||||
this.init();
|
|
||||||
|
|
||||||
// 调用刷脸认证
|
|
||||||
// ChsCheckResponse userInfo = padChsPayService.getInfoByFace(new ChsModel());
|
|
||||||
|
|
||||||
ChsCheckResponse userInfo = new ChsCheckResponse()
|
|
||||||
.setIdNo("530111199701031117")
|
|
||||||
.setUserName("薛家俊")
|
|
||||||
.setIdType("01")
|
|
||||||
.setEcToken("530000fec5tp6km4s626a3720a00005186b127")
|
|
||||||
.setAuthNo("ano3954912217759795201530000");
|
|
||||||
|
|
||||||
JSONObject params = new JSONObject()
|
|
||||||
.fluentPut("orgCodg", "") // 机构编码
|
|
||||||
.fluentPut("feeType", "") // 费用类型
|
|
||||||
.fluentPut("orgId", ynChsConfig.getFixmeDinsCode()) // 电子凭证机构号
|
|
||||||
.fluentPut("idType", userInfo.getIdType()) // 证件类别
|
|
||||||
.fluentPut("idNo", userInfo.getIdNo()) // 证件号码
|
|
||||||
.fluentPut("userName", userInfo.getUserName()) // 用户姓名
|
|
||||||
.fluentPut("ecToken", userInfo.getEcToken()) // 电子凭证授权 ecToken
|
|
||||||
.fluentPut("authNo", userInfo.getAuthNo()); // 实人认证流水号
|
|
||||||
JSONObject inputData = new JSONObject().fluentPut("input", new JSONObject().fluentPut("data", params));
|
|
||||||
String inputDataStr = inputData.toString(SerializerFeature.WriteNullStringAsEmpty);
|
|
||||||
|
|
||||||
Pointer errMsg = new Memory(1024 * 10);
|
|
||||||
Pointer outputData = new Memory(1024 * 10);
|
|
||||||
|
|
||||||
log.debug("[LOG1591][placeOrderByDll][云南省局医保DLL][BusinessHandle][终端获取支付令牌] 请求入参: {}", inputDataStr);
|
|
||||||
int state = dll.BusinessHandle(ynChsConfig.getFixmeDinsCode(), ynChsConfig.getInfoSysCode(), ynChsConfig.getInfoSysSign(), inputDataStr, outputData, errMsg);
|
|
||||||
String errMsgStr = errMsg.getString(0, CharsetConst.GB2312);
|
|
||||||
String outputDataStr = outputData.getString(0, CharsetConst.GB2312);
|
|
||||||
log.debug("[LOG1591][placeOrderByDll][云南省局医保DLL][BusinessHandle][终端获取支付令牌] 请求出参 data:{} errMsg:{}", outputDataStr, errMsgStr);
|
|
||||||
|
|
||||||
if (state != 0) {
|
|
||||||
throw new RuntimeException("终端获取支付令牌失败:" + errMsgStr);
|
|
||||||
}
|
|
||||||
|
|
||||||
JSONObject result = JSONObject.parseObject(outputDataStr);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void init() {
|
|
||||||
log.debug("[LOG4945][initPrinter][云南省局医保DLL][Init] 开始");
|
|
||||||
Pointer errMsg = new Memory(1024 * 10);
|
|
||||||
int state = dll.Init(ynChsConfig.getFixmeDinsCode(), ynChsConfig.getInfoSysCode(), ynChsConfig.getInfoSysSign(), ynChsConfig.getUrl(), errMsg);
|
|
||||||
String errMsgStr = errMsg.getString(0, CharsetConst.GB2312);
|
|
||||||
log.debug("[LOG4945][initPrinter][云南省局医保DLL][Init] 结束 state:{} errMsg:{}", state, errMsgStr);
|
|
||||||
|
|
||||||
if (state != 0) {
|
|
||||||
throw new RuntimeException("初始化医保动态库失败:" + errMsgStr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,234 @@
|
|||||||
|
package com.dpkj.modules.chs.ynchs.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.DatePattern;
|
||||||
|
import cn.hutool.core.date.DateTime;
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.hutool.core.util.RandomUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||||
|
import com.dpkj.common.config.PadChsConfig;
|
||||||
|
import com.dpkj.common.config.YnChsConfig;
|
||||||
|
import com.dpkj.common.constant.CharsetConst;
|
||||||
|
import com.dpkj.common.utils.IDGenerator;
|
||||||
|
import com.dpkj.modules.chs.padchs.constant.ChsDictEnum;
|
||||||
|
import com.dpkj.modules.chs.padchs.constant.NationECCodeConst;
|
||||||
|
import com.dpkj.modules.chs.padchs.response.ChsCheckResponse;
|
||||||
|
import com.dpkj.modules.chs.padchs.service.IPadChsPayService;
|
||||||
|
import com.dpkj.modules.chs.ynchs.constant.YnchsConst;
|
||||||
|
import com.dpkj.modules.chs.ynchs.dll.YnChsPayDll;
|
||||||
|
import com.dpkj.modules.chs.ynchs.service.IYnchspayByDllService;
|
||||||
|
import com.sun.jna.Memory;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Auther: 萧道子
|
||||||
|
* @Date: 2025/8/7 14:46
|
||||||
|
* @Description:
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class YnchspayByDllServiceImpl implements IYnchspayByDllService {
|
||||||
|
|
||||||
|
// 缓冲区大小 1M
|
||||||
|
private final long bufferSize = 1024 * 1024;
|
||||||
|
|
||||||
|
private YnChsPayDll.EcDll dll;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private YnChsConfig ynChsConfig;
|
||||||
|
@Autowired
|
||||||
|
private PadChsConfig chsPadConfig;
|
||||||
|
@Autowired
|
||||||
|
private IPadChsPayService padChsPayService;
|
||||||
|
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void postConstruct() {
|
||||||
|
log.info("[YnchspayByWebapiServiceImpl][postConstruct][云南省局医保DLL] 初始化动态链接库");
|
||||||
|
try {
|
||||||
|
dll = YnChsPayDll.instance();
|
||||||
|
} catch (YnChsPayDll.DllRegistrationException e) {
|
||||||
|
log.error("[YnchspayByWebapiServiceImpl][postConstruct][云南省局医保DLL] 加载失败:{}", e.getMessage());
|
||||||
|
throw new RuntimeException("云南省局医保DLL库加载失败:" + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChsCheckResponse getUserByFace() {
|
||||||
|
JSONObject ecinfo = this.chsApi1191();
|
||||||
|
return new ChsCheckResponse()
|
||||||
|
.setAuthNo(ecinfo.getString("authno"))
|
||||||
|
.setEcToken(ecinfo.getString("ectoken"))
|
||||||
|
.setEcIndexNo(ecinfo.getString("ecIndexno"))
|
||||||
|
.setEmail(ecinfo.getString("email"))
|
||||||
|
.setUserName(ecinfo.getString("username"))
|
||||||
|
.setIdNo(ecinfo.getString("idno"))
|
||||||
|
.setIdType(ecinfo.getString("psn_cert_type"))
|
||||||
|
.setInsuOrg(ecinfo.getString("insuorg"))
|
||||||
|
.setBirthday(ecinfo.getString("birthday"))
|
||||||
|
.setGender(ecinfo.getString("gender"))
|
||||||
|
.setNationality(ecinfo.getString("nationality"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 身份认证
|
||||||
|
*
|
||||||
|
* @return com.alibaba.fastjson.JSONObject
|
||||||
|
* @author 萧道子 2025/10/24
|
||||||
|
*/
|
||||||
|
public JSONObject chsApi1191() {
|
||||||
|
JSONObject inputData = new JSONObject()
|
||||||
|
.fluentPut("mdtrt_cert_type", "01") // 就诊凭证类型
|
||||||
|
.fluentPut("cardtype", "") // 卡片类型
|
||||||
|
.fluentPut("businesstype", ChsDictEnum.BusinessType.YY_301.str()) // 用码业务类型
|
||||||
|
.fluentPut("operatorid", chsPadConfig.getOperatorId()) // 收款员编号
|
||||||
|
.fluentPut("operatorname", chsPadConfig.getOperatorName()) // 收款员姓名
|
||||||
|
.fluentPut("officeid", chsPadConfig.getOfficeId()) // 医保科室编号
|
||||||
|
.fluentPut("officename", chsPadConfig.getOfficeName()) // 科室名称
|
||||||
|
.fluentPut("transType", NationECCodeConst.TRANSTYPE_ALICHS_AUTH) // 交易类型 刷脸
|
||||||
|
.fluentPut("deviceType", "SelfService") // 设备类型
|
||||||
|
.fluentPut("outBizNo", IDGenerator.getSnowflakeIdToStr()) // 定点医药机构本次业务流水号
|
||||||
|
.fluentPut("extData", ""); // 扩展参数
|
||||||
|
JSONObject result = this.sendDll(YnchsConst.URL_1191, "1191", inputData);
|
||||||
|
JSONObject ecinfo = result.getJSONObject("ecinfo");
|
||||||
|
return ecinfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 人员信息获取
|
||||||
|
*
|
||||||
|
* @param val :
|
||||||
|
* @return com.alibaba.fastjson.JSONObject
|
||||||
|
* @author 萧道子 2025/10/23
|
||||||
|
*/
|
||||||
|
public JSONObject chsApi1101(ChsCheckResponse val) {
|
||||||
|
JSONObject inputData = new JSONObject()
|
||||||
|
.fluentPut("mdtrt_cert_type", "01") // 就诊凭证类型
|
||||||
|
.fluentPut("mdtrt_cert_no", val.getEcToken()) // 就诊凭证编号-电子凭证令牌
|
||||||
|
.fluentPut("card_sn", "") // 卡识别码
|
||||||
|
.fluentPut("begntime", "") // 开始时间-获取历史参保信息时传入
|
||||||
|
.fluentPut("psn_cert_type", val.getIdType()) // 人员证件类型-01代表身份证
|
||||||
|
.fluentPut("certno", val.getIdNo()) // 证件号码
|
||||||
|
.fluentPut("psn_name", val.getUserName()); // 人员姓名
|
||||||
|
JSONObject result = this.sendDll(YnchsConst.URL_1101, "1101", inputData);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化函数
|
||||||
|
*
|
||||||
|
* @param apiUrl :
|
||||||
|
* @return void
|
||||||
|
* @author 萧道子 2025/10/24
|
||||||
|
*/
|
||||||
|
private void init(String apiUrl) {
|
||||||
|
log.debug("[LOG4945][initPrinter][云南省局医保DLL][Init] 开始");
|
||||||
|
String url = ynChsConfig.getUrl() + apiUrl;
|
||||||
|
Memory errPointer = new Memory(bufferSize);
|
||||||
|
int state = dll.Init(ynChsConfig.getFixmeDinsCode(), ynChsConfig.getInfoSysCode(), ynChsConfig.getInfoSysSign(), url, errPointer);
|
||||||
|
String errValueStr = errPointer.getString(0, CharsetConst.GB2312);
|
||||||
|
errPointer.close();
|
||||||
|
log.debug("[LOG4945][initPrinter][云南省局医保DLL][Init] 结束 state:{} errMsg:{}", state, errValueStr);
|
||||||
|
if (state != 0) {
|
||||||
|
throw new RuntimeException("初始化医保动态库失败:" + errValueStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发起请求
|
||||||
|
*
|
||||||
|
* @param url : 请求地址
|
||||||
|
* @param infno : 交易编码
|
||||||
|
* @param inputData : 请求值
|
||||||
|
* @return com.alibaba.fastjson.JSONObject
|
||||||
|
* @author 萧道子 2025/10/23
|
||||||
|
*/
|
||||||
|
private JSONObject sendDll(String url, String infno, JSONObject inputData) {
|
||||||
|
// 一、初始化
|
||||||
|
this.init(url);
|
||||||
|
|
||||||
|
// 二、设置公共请求参数
|
||||||
|
String infoSysSign = ynChsConfig.getInfoSysSign();
|
||||||
|
String fixmeDinsCode = ynChsConfig.getFixmeDinsCode();
|
||||||
|
String infoSysCode = ynChsConfig.getInfoSysCode();
|
||||||
|
String cityCode = ynChsConfig.getCityCode();
|
||||||
|
String fixmeDinsName = ynChsConfig.getFixmeDinsName();
|
||||||
|
|
||||||
|
String nonce = IDGenerator.getSnowflakeIdToStr();
|
||||||
|
DateTime date = DateUtil.date();
|
||||||
|
String timestamp = DateUtil.format(date, DatePattern.PURE_DATETIME_PATTERN);
|
||||||
|
|
||||||
|
String msgid = fixmeDinsCode + timestamp + RandomUtil.randomNumbers(4);
|
||||||
|
|
||||||
|
// 请求体参数
|
||||||
|
JSONObject params = new JSONObject()
|
||||||
|
.fluentPut("infno", infno) // 交易编号
|
||||||
|
.fluentPut("msgid", msgid) // 发送方报文ID 定点医药机构编号(12)+时间(14)+顺序号(4) 时间格式:yyyyMMddHHmmss
|
||||||
|
.fluentPut("mdtrtarea_admvs", cityCode) // 就医地医保区划
|
||||||
|
.fluentPut("insuplc_admdvs", "") // 参保地医保区划
|
||||||
|
.fluentPut("recer_sys_code", "yinyitong") // 接收方系统代码
|
||||||
|
.fluentPut("dev_no", "") // 设备编号
|
||||||
|
.fluentPut("dev_safe_info", "") // 设备安全信息
|
||||||
|
.fluentPut("cainfo", "") // 数字签名信息
|
||||||
|
.fluentPut("signtype", "") // 签名类型
|
||||||
|
.fluentPut("infver", "V1.0") // 接口版本号
|
||||||
|
.fluentPut("opter_type", "2") // 经办人类别 1-经办人;2-自助终端;3-移动终端
|
||||||
|
.fluentPut("opter", "test") // 经办人
|
||||||
|
.fluentPut("opter_name", "test") // 经办人姓名
|
||||||
|
.fluentPut("inf_time", DateUtil.format(date, DatePattern.NORM_DATETIME_PATTERN)) // 交易时间
|
||||||
|
.fluentPut("fixmedins_code", fixmeDinsCode) // 定点医药机构编号
|
||||||
|
.fluentPut("fixmedins_name", fixmeDinsName) // 定点医药机构名称
|
||||||
|
.fluentPut("sign_no", nonce) // 交易签到流水号
|
||||||
|
.fluentPut("input", new JSONObject().fluentPut("data", inputData)); // 交易输入
|
||||||
|
String paramsStr = params.toString(SerializerFeature.WriteNullStringAsEmpty);
|
||||||
|
|
||||||
|
// 三、发起请求
|
||||||
|
log.debug("[LOG1591][sendHttp][云南省局医保DLL][{}] 请求入参: {}", infno, paramsStr);
|
||||||
|
|
||||||
|
Memory errPointer = new Memory(bufferSize);
|
||||||
|
Memory outPointer = new Memory(bufferSize);
|
||||||
|
int state = dll.BusinessHandle(fixmeDinsCode, infoSysCode, infoSysSign, paramsStr, outPointer, errPointer);
|
||||||
|
String errValueStr = errPointer.getString(0, CharsetConst.GB2312);
|
||||||
|
String outValueStr = outPointer.getString(0, CharsetConst.GB2312);
|
||||||
|
errPointer.close();
|
||||||
|
outPointer.close();
|
||||||
|
|
||||||
|
log.debug("[LOG1591][sendHttp][云南省局医保DLL][{}] 请求出参 state:{} errMsg:{} data:{} ", infno, state, errValueStr, outValueStr);
|
||||||
|
|
||||||
|
// 四、处理响应
|
||||||
|
if (state != 0) {
|
||||||
|
log.error("[LOG8761][sendDll][云南省局医保DLL][{}] 医保通用接口BusinessHandle调用失败 state:{}", infno, state);
|
||||||
|
throw new RuntimeException("医保接口请求失败!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StrUtil.isEmpty(outValueStr)) {
|
||||||
|
log.error("[LOG8762][sendDll][云南省局医保DLL][{}] 医保接口响应数据为空 state:{} ", infno, state);
|
||||||
|
throw new RuntimeException("医保接口响应数据为空:" + errValueStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject result;
|
||||||
|
try {
|
||||||
|
result = JSONObject.parseObject(outValueStr);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("[LOG4410][sendDll][云南省局医保DLL][{}] 医保响应数转JSON失败 ERR:{}", infno, e.getMessage());
|
||||||
|
throw new RuntimeException("医保响应数据解析失败!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.getInteger("infcode") != 0) {
|
||||||
|
String errmsg = result.getString("err_msg");
|
||||||
|
log.error("[LOG4411][sendDll][云南省局医保DLL][{}] 医保方系统错误 ERR:{}", infno, errmsg);
|
||||||
|
throw new RuntimeException("医保请求失败:" + errmsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject output = result.getJSONObject("output");
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,233 @@
|
|||||||
|
package com.dpkj.modules.chs.ynchs.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.DatePattern;
|
||||||
|
import cn.hutool.core.date.DateTime;
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.hutool.core.util.RandomUtil;
|
||||||
|
import cn.hutool.crypto.SecureUtil;
|
||||||
|
import cn.hutool.http.HttpRequest;
|
||||||
|
import cn.hutool.http.HttpResponse;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||||
|
import com.dpkj.common.config.YnChsConfig;
|
||||||
|
import com.dpkj.common.utils.IDGenerator;
|
||||||
|
import com.dpkj.modules.chs.padchs.response.ChsCheckResponse;
|
||||||
|
import com.dpkj.modules.chs.padchs.service.IPadChsPayService;
|
||||||
|
import com.dpkj.modules.chs.ynchs.constant.YnchsConst;
|
||||||
|
import com.dpkj.modules.chs.ynchs.service.IYnchspayByWebapiService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Auther: 萧道子
|
||||||
|
* @Date: 2025/8/7 14:46
|
||||||
|
* @Description:
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class YnchspayByWebapiServiceImpl implements IYnchspayByWebapiService {
|
||||||
|
@Autowired
|
||||||
|
private YnChsConfig ynChsConfig;
|
||||||
|
@Autowired
|
||||||
|
private IPadChsPayService padChsPayService;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void postConstruct() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 人员信息获取
|
||||||
|
*
|
||||||
|
* @param val :
|
||||||
|
* @return com.alibaba.fastjson.JSONObject
|
||||||
|
* @author 萧道子 2025/10/23
|
||||||
|
*/
|
||||||
|
private JSONObject chsApi1101(ChsCheckResponse val) {
|
||||||
|
JSONObject inputData = new JSONObject()
|
||||||
|
.fluentPut("mdtrt_cert_type", "01") // 就诊凭证类型
|
||||||
|
.fluentPut("mdtrt_cert_no", val.getEcToken()) // 就诊凭证编号-电子凭证令牌
|
||||||
|
.fluentPut("card_sn", "") // 卡识别码
|
||||||
|
.fluentPut("begntime", "") // 开始时间-获取历史参保信息时传入
|
||||||
|
.fluentPut("psn_cert_type", val.getIdType()) // 人员证件类型-01代表身份证
|
||||||
|
.fluentPut("certno", val.getIdNo()) // 证件号码
|
||||||
|
.fluentPut("psn_name", val.getUserName()); // 人员姓名
|
||||||
|
|
||||||
|
JSONObject result = this.sendHttp(YnchsConst.URL_1101, "1101", inputData);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单支付-费用明细上传
|
||||||
|
*
|
||||||
|
* @return com.alibaba.fastjson.JSONObject
|
||||||
|
* @author 萧道子 2025/10/23
|
||||||
|
*/
|
||||||
|
private JSONObject chsApi6201(JSONObject val) {
|
||||||
|
String fixmeDinsCode = ynChsConfig.getFixmeDinsCode();
|
||||||
|
JSONObject params = new JSONObject()
|
||||||
|
.fluentPut("orgCodg", fixmeDinsCode) // 机构编码-医保分配 字符型40-Y
|
||||||
|
.fluentPut("orgId", "") // 电子凭证机构号-电子凭证中台分配,待机构电子凭证建设完毕后可获取该机构号 字符型40
|
||||||
|
.fluentPut("psnNo", "") // 人员编号 字符型30-Y
|
||||||
|
.fluentPut("insutype", "") // 险种类型-字典险种类型 (insutype) 字符型6-Y
|
||||||
|
.fluentPut("medOrgOrd", "") // 医疗机构订单号-院内产生惟一流水,可关联到一次结算记录,结算成功回调入参返回 字符型40-Y
|
||||||
|
.fluentPut("initRxOrd", "") // 要续方的原处方流水-rxCircFlag 为1时必传,续方时必传 字符型40
|
||||||
|
.fluentPut("rxCircFlag", "") // 电子处方流转标志-1:电子处方 ,0不是电子处方,默认0 字符型1
|
||||||
|
.fluentPut("begntime", "") // 开始时间-挂号时间yyyy-MM-dd HH:mm:ss 字符型19-Y
|
||||||
|
.fluentPut("idNo", "") // 证件号码 字符型40-Y
|
||||||
|
.fluentPut("userName", "") // 用户姓名 字符型40-Y
|
||||||
|
.fluentPut("idType", "") // 证件类别-字典人员证件类型(psn_cert_type) 字符型3-Y
|
||||||
|
.fluentPut("ecToken", "") // 电子凭证授权ecToken-电子凭证解码返回 字符型64-Y
|
||||||
|
.fluentPut("insuCode", "") // 就诊参保地行政区划-同核心FSI接口入参mdtrtarea_admvs 字符型6-Y
|
||||||
|
.fluentPut("iptOtpNo", "") // 住院/门诊号-院内唯一流水 字符型30-Y
|
||||||
|
.fluentPut("atddrNo", "") // 医师编码 字符型30
|
||||||
|
.fluentPut("drName", "") // 医师姓名 字符型50
|
||||||
|
.fluentPut("deptCode", "") // 科室编码 字符型30
|
||||||
|
.fluentPut("deptName", "") // 科室名称 字符型100-Y
|
||||||
|
.fluentPut("caty", "") // 科别 字符型6-Y
|
||||||
|
.fluentPut("mdtrtId", "") // 就诊ID 字符型30
|
||||||
|
.fluentPut("medType", "") // 医疗类别-字典医疗类别(med_type) 字符型6-Y
|
||||||
|
.fluentPut("feeType", "") // 费用类型-字典费用类型(feeType) 字符型3-Y
|
||||||
|
.fluentPut("medfeeSumamt", "") // 医疗费总额 数值型16,2-Y
|
||||||
|
.fluentPut("acctUsedFlag", "") // 个人账户使用标志-药店上传费用时必填 字符型1-Y
|
||||||
|
.fluentPut("mainCondDscr", "") // 主要病情描述 字符型1000
|
||||||
|
.fluentPut("diseCodg", "") // 病种编码-按照标准编码填写:按病种结算病种目录代码(bydise_setl_list_code)、门诊慢特病病种目录代码(opsp_dise_cod) 字符型30-Y
|
||||||
|
.fluentPut("diseName", "") // 病种名称 字符型500-Y
|
||||||
|
.fluentPut("psnSetlway", "") // 个人结算方式 字符型6-Y
|
||||||
|
.fluentPut("chrgBchno", "") // 收费批次号 字符型30-Y
|
||||||
|
.fluentPut("pubHospRfomFlag", "") // 公立医院改革标志-可参考FSI的接口要求 字符型6-Y
|
||||||
|
.fluentPut("invono", "") // 发票号 字符型20
|
||||||
|
.fluentPut("endtime", "") // 出院时间-yyyy-MM-dd HH:mm:ss 字符型19
|
||||||
|
.fluentPut("fulamtOwnpayAmt", "") // 全自费金额-住院结算时需要 数值型16,2
|
||||||
|
.fluentPut("overlmtSelfpay", "") // 超限价金额-住院结算时需要 数值型16,2
|
||||||
|
.fluentPut("preselfpayAmt", "") // 先行自付金额-住院结算时需要 数值型16,2
|
||||||
|
.fluentPut("inscpScpAmt", "") // 符合政策范围金额-住院结算时需要 数值型16,2
|
||||||
|
.fluentPut("oprnOprtCode", "") // 手术操作代码-住院结算时需要 字符型30
|
||||||
|
.fluentPut("oprnOprtName", "") // 手术操作名称-住院结算时需要 字符型500
|
||||||
|
.fluentPut("fpscNo", "") // 计划生育服务证号-住院结算时需要 字符型50
|
||||||
|
.fluentPut("latechbFlag", "") // 晚育标志-住院结算时需要 字符型3
|
||||||
|
.fluentPut("gesoVal", "") // 孕周数-住院结算时需要 数值型2
|
||||||
|
.fluentPut("fetts", "") // 胎次-住院结算时需要 数值型3-Y
|
||||||
|
.fluentPut("fetusCnt", "") // 胎儿数-住院结算时需要 数值型3
|
||||||
|
.fluentPut("pretFlag", "") // 早产标志-住院结算时需要 字符型3
|
||||||
|
.fluentPut("birctrlType", "") // 计划生育手术类别-生育门诊按需录入 字符型6
|
||||||
|
.fluentPut("birctrlMatnDate", "") // 计划生育手术或生育日期-生育门诊按需录入,yyyy-MM-dd 字符型10
|
||||||
|
.fluentPut("copFlag", "") // 伴有并发症标志-住院结算时需要 字符型3
|
||||||
|
.fluentPut("dscgDeptCodg", "") // 出院科室编码-住院结算时需要 字符型30
|
||||||
|
.fluentPut("dscgDeptName", "") // 出院科室名称-住院结算时需要 字符型100
|
||||||
|
.fluentPut("dscgDed", "") // 出院床位-住院结算时需要 字符型50
|
||||||
|
.fluentPut("dscgWay", "") // 离院方式-住院结算时需要 字符型8
|
||||||
|
.fluentPut("dieDate", "") // 死亡日期-yyyy-MM-dd 字符型10
|
||||||
|
.fluentPut("matnType", "") // 生育类别-住院结算时需要 字符型6-Y
|
||||||
|
.fluentPut("expContent", "") // 扩展参数-可参考FSI的接口要求 字符型4000
|
||||||
|
.fluentPut("midSetlFlag", "") // 中途结算标志-字典中途结算标志(mid_setl_flag) 字符型3
|
||||||
|
.fluentPut("diseinfoList", "") // 诊断或症状明细-Y-见下方diseinfoList定义
|
||||||
|
.fluentPut("feedetailList", "") // 费用明细-Y-见下方feedetailList定义
|
||||||
|
.fluentPut("admDiagDscr", "") // 入院诊断描述-住院结算时需要 字符型200
|
||||||
|
.fluentPut("admDeptCodg", "") // 入院科室编码-住院结算时需要 字符型30
|
||||||
|
.fluentPut("admDeptName", "") // 入院科室名称-住院结算时需要 字符型100
|
||||||
|
.fluentPut("admBed", "") // 入院床位-住院结算时需要 字符型30
|
||||||
|
.fluentPut("payAuthNo", "") // 支付授权码-线上授权返回 字符型40
|
||||||
|
.fluentPut("uldLatlnt", "") // 经纬度-格式:经度,纬度如:118.096435,24.485407定位失败情况下传:0,0 字符型21
|
||||||
|
.fluentPut("mdtrtCertType", "") // 就诊凭证类型-“00” 无就诊介质,“01” 电子凭证,“02”居民身份证,“03”社会保障卡 字符型2
|
||||||
|
.fluentPut("insuplcAdmdvs", "") // 用户参保地行政区划-同核心FSI参数insuplc_admdvs 字符型6-Y
|
||||||
|
.fluentPut("dscgFlag", "") // 出院登记标志-住院结算时需要,0:由中台调用出院登记1:由定点调用出院登记 字符型1
|
||||||
|
.fluentPut("opterType", "") // 操作员类别-为空时使用移动支付中心默认 字符型10
|
||||||
|
.fluentPut("devSafeInfo", "") // 设备安全编码-为空时使用移动支付中心默默认 字符型30
|
||||||
|
.fluentPut("setlType", "") // 结算类别-OWN:自费类别放空默认为医保订单 字符型30
|
||||||
|
.fluentPut("fixmedinsMdtrtId", "") // 医药机构就诊ID-setlType为OWN且当地要求自费数据要上传核心时必传,参考FSI要求 字符型30
|
||||||
|
.fluentPut("ownpayType", "") // 自费类型-setlType为OWN且当地要求自费数据要上传核心时传可按需传,参考FSI要求 字符型3
|
||||||
|
.fluentPut("elecBillnoCode", "") // 电子票据号码-setlType为OWN且当地要求自费数据要上传核心时传可按需传,参考FSI要求。如果是纸质发票则填写纸质发票号码 字符型50
|
||||||
|
.fluentPut("elecBillCode", "") // 电子票据代码-setlType为OWN且当地要求自费数据要上传核心时传可按需传,参考FSI要求 字符型50
|
||||||
|
.fluentPut("elecBillChkcode", "") // 电子票据校验码-setlType为OWN且当地要求自费数据要上传核心时传可按需传,参考FSI要求 字符型6
|
||||||
|
.fluentPut("onlineDrugChnlAppId", "") // 线上购药渠道id-线上购药业务时,必传,见移动支付反馈单 字符型40
|
||||||
|
.fluentPut("drugCrtfCodg", "") // 线上购药渠道认证编码-线上购药业务时,必传,见移动支付线上购药反馈单 字符型40
|
||||||
|
;
|
||||||
|
|
||||||
|
JSONObject result = sendHttp(YnchsConst.URL_6201, "6201", params);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发起请求
|
||||||
|
*
|
||||||
|
* @param url :
|
||||||
|
* @param infno :
|
||||||
|
* @param inputData :
|
||||||
|
* @return com.alibaba.fastjson.JSONObject
|
||||||
|
* @author 萧道子 2025/10/23
|
||||||
|
*/
|
||||||
|
private JSONObject sendHttp(String url, String infno, JSONObject inputData) {
|
||||||
|
|
||||||
|
// 请求头参数
|
||||||
|
String infoSysSign = ynChsConfig.getInfoSysSign();
|
||||||
|
String fixmeDinsCode = ynChsConfig.getFixmeDinsCode();
|
||||||
|
String infoSysCode = ynChsConfig.getInfoSysCode();
|
||||||
|
String baseUrl = ynChsConfig.getUrl();
|
||||||
|
String cityCode = ynChsConfig.getCityCode();
|
||||||
|
String fixmeDinsName = ynChsConfig.getFixmeDinsName();
|
||||||
|
|
||||||
|
String nonce = IDGenerator.getSnowflakeIdToStr();
|
||||||
|
DateTime date = DateUtil.date();
|
||||||
|
String timestamp = DateUtil.format(date, DatePattern.PURE_DATETIME_PATTERN);
|
||||||
|
String signature = SecureUtil.sha256(timestamp + infoSysSign + nonce);
|
||||||
|
|
||||||
|
String msgid = fixmeDinsCode + timestamp + RandomUtil.randomNumbers(4);
|
||||||
|
|
||||||
|
// 请求体参数
|
||||||
|
JSONObject params = new JSONObject()
|
||||||
|
.fluentPut("infno", infno) // 交易编号
|
||||||
|
.fluentPut("msgid", msgid) // 发送方报文ID 定点医药机构编号(12)+时间(14)+顺序号(4) 时间格式:yyyyMMddHHmmss
|
||||||
|
.fluentPut("mdtrtarea_admvs", cityCode) // 就医地医保区划
|
||||||
|
.fluentPut("insuplc_admdvs", "") // 参保地医保区划
|
||||||
|
.fluentPut("recer_sys_code", "yinyitong") // 接收方系统代码
|
||||||
|
.fluentPut("dev_no", "") // 设备编号
|
||||||
|
.fluentPut("dev_safe_info", "") // 设备安全信息
|
||||||
|
.fluentPut("cainfo", "") // 数字签名信息
|
||||||
|
.fluentPut("signtype", "") // 签名类型
|
||||||
|
.fluentPut("infver", "V1.0") // 接口版本号
|
||||||
|
.fluentPut("opter_type", 3) // 经办人类别 1-经办人;2-自助终端;3-移动终端
|
||||||
|
.fluentPut("opter", "test") // 经办人
|
||||||
|
.fluentPut("opter_name", "test") // 经办人姓名
|
||||||
|
.fluentPut("inf_time", DateUtil.format(date, DatePattern.NORM_DATETIME_PATTERN)) // 交易时间
|
||||||
|
.fluentPut("fixmedins_code", fixmeDinsCode) // 定点医药机构编号
|
||||||
|
.fluentPut("fixmedins_name", fixmeDinsName) // 定点医药机构名称
|
||||||
|
.fluentPut("sign_no", nonce) // 交易签到流水号
|
||||||
|
.fluentPut("input", new JSONObject().fluentPut("data", inputData)); // 交易输入
|
||||||
|
String paramsStr = params.toString(SerializerFeature.WriteNullStringAsEmpty);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 请求
|
||||||
|
log.debug("[LOG7900][sendHttp][云南省局医保-API][{}] 请求入参: {}", infno, paramsStr);
|
||||||
|
HttpResponse response = HttpRequest.post(baseUrl + url)
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.header("fixmedins_code", fixmeDinsCode) // 医保机构编码
|
||||||
|
.header("infosyscode", infoSysCode) // 服务商统一社会信用代码
|
||||||
|
.header("hsf_nonce", nonce) // 校验码 非重复的随机字符串(十分钟内不能重复)
|
||||||
|
.header("hsf_timestamp", timestamp) // 当前时间戳(秒)
|
||||||
|
.header("hsf_signature", signature) // 加密生成的签名
|
||||||
|
.body(paramsStr)
|
||||||
|
.execute();
|
||||||
|
String resultBody = response.body();
|
||||||
|
log.debug("[LOG7900][sendHttp][云南省局医保-API][{}] 请求出参: {}", infno, resultBody);
|
||||||
|
// 释放资源
|
||||||
|
response.close();
|
||||||
|
|
||||||
|
// 转换参数
|
||||||
|
JSONObject result = JSONObject.parseObject(resultBody);
|
||||||
|
return result;
|
||||||
|
} catch (Exception e) {
|
||||||
|
// e.printStackTrace();
|
||||||
|
log.error("[LOG3010][sendHttp][云南省局医保-API][{}] 请求失败 ERR:{}", infno, e.getMessage());
|
||||||
|
throw new RuntimeException("医保接口请求失败!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
39
src/main/java/com/dpkj/modules/chs/ynchs/utils/BCUtils.java
Normal file
39
src/main/java/com/dpkj/modules/chs/ynchs/utils/BCUtils.java
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
package com.dpkj.modules.chs.ynchs.utils;
|
||||||
|
|
||||||
|
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||||
|
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.NoSuchPaddingException;
|
||||||
|
import java.security.*;
|
||||||
|
|
||||||
|
public class BCUtils {
|
||||||
|
|
||||||
|
static {
|
||||||
|
if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME)==null){
|
||||||
|
Security.addProvider(new BouncyCastleProvider());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Cipher getCipher(final String algorithm) {
|
||||||
|
try {
|
||||||
|
return Cipher.getInstance(algorithm, BouncyCastleProvider.PROVIDER_NAME);
|
||||||
|
} catch (final NoSuchAlgorithmException | NoSuchPaddingException | NoSuchProviderException e) {
|
||||||
|
throw new IllegalArgumentException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MessageDigest getMessageDigest(final String algorithm) {
|
||||||
|
try {
|
||||||
|
return MessageDigest.getInstance(algorithm, BouncyCastleProvider.PROVIDER_NAME);
|
||||||
|
} catch (final NoSuchAlgorithmException|NoSuchProviderException e) {
|
||||||
|
throw new IllegalArgumentException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static Signature getSignature(final String algorithm) {
|
||||||
|
try {
|
||||||
|
return Signature.getInstance(algorithm, BouncyCastleProvider.PROVIDER_NAME);
|
||||||
|
} catch (final NoSuchAlgorithmException|NoSuchProviderException e) {
|
||||||
|
throw new IllegalArgumentException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
361
src/main/java/com/dpkj/modules/chs/ynchs/utils/EasyGmUtils.java
Normal file
361
src/main/java/com/dpkj/modules/chs/ynchs/utils/EasyGmUtils.java
Normal file
@@ -0,0 +1,361 @@
|
|||||||
|
package com.dpkj.modules.chs.ynchs.utils;
|
||||||
|
|
||||||
|
import org.bouncycastle.asn1.ASN1EncodableVector;
|
||||||
|
import org.bouncycastle.asn1.ASN1Integer;
|
||||||
|
import org.bouncycastle.asn1.ASN1Sequence;
|
||||||
|
import org.bouncycastle.asn1.DERSequence;
|
||||||
|
import org.bouncycastle.asn1.gm.GMNamedCurves;
|
||||||
|
import org.bouncycastle.asn1.x9.X9ECParameters;
|
||||||
|
import org.bouncycastle.crypto.InvalidCipherTextException;
|
||||||
|
import org.bouncycastle.crypto.engines.SM2Engine;
|
||||||
|
import org.bouncycastle.crypto.params.ECDomainParameters;
|
||||||
|
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
|
||||||
|
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
|
||||||
|
import org.bouncycastle.crypto.params.ParametersWithRandom;
|
||||||
|
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
|
||||||
|
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
|
||||||
|
import org.bouncycastle.jcajce.spec.SM2ParameterSpec;
|
||||||
|
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||||
|
import org.bouncycastle.jce.spec.ECParameterSpec;
|
||||||
|
import org.bouncycastle.jce.spec.ECPrivateKeySpec;
|
||||||
|
import org.bouncycastle.jce.spec.ECPublicKeySpec;
|
||||||
|
import org.bouncycastle.util.BigIntegers;
|
||||||
|
import org.bouncycastle.util.encoders.Hex;
|
||||||
|
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.security.Key;
|
||||||
|
import java.security.PrivateKey;
|
||||||
|
import java.security.PublicKey;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.security.Signature;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: fuchengmu
|
||||||
|
* @Date: 2019-10-05 14:58
|
||||||
|
* <p>
|
||||||
|
* 用BC的注意点:
|
||||||
|
* 这个版本的BC对SM3withSM2的结果为asn1格式的r和s,如果需要直接拼接的r||s需要自己转换。下面rsAsn1ToPlainByteArray、rsPlainByteArrayToAsn1就在干这事。
|
||||||
|
* 这个版本的BC对SM2的结果为C1||C2||C3,据说为旧标准,新标准为C1||C3||C2,用新标准的需要自己转换。下面changeC1C2C3ToC1C3C2、changeC1C3C2ToC1C2C3就在干这事。
|
||||||
|
*/
|
||||||
|
public class EasyGmUtils {
|
||||||
|
private static X9ECParameters x9ECParameters = GMNamedCurves.getByName("sm2p256v1");
|
||||||
|
private static ECDomainParameters ecDomainParameters = new ECDomainParameters(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN());
|
||||||
|
private static ECParameterSpec ecParameterSpec = new ECParameterSpec(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN());
|
||||||
|
|
||||||
|
|
||||||
|
public static byte[] signSm3WithSm2(byte[] msg, byte[] userId, byte[] privateKeyBytes) {
|
||||||
|
BCECPrivateKey bcecPrivateKey = getPrivatekeyFromD(BigIntegers.fromUnsignedByteArray(privateKeyBytes));
|
||||||
|
return signSm3WithSm2(msg, userId, bcecPrivateKey);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param msg
|
||||||
|
* @param userId
|
||||||
|
* @param privateKey
|
||||||
|
* @return r||s,直接拼接byte数组的rs
|
||||||
|
*/
|
||||||
|
public static byte[] signSm3WithSm2(byte[] msg, byte[] userId, PrivateKey privateKey) {
|
||||||
|
return rsAsn1ToPlainByteArray(signSm3WithSm2Asn1Rs(msg, userId, privateKey));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param msg
|
||||||
|
* @param userId
|
||||||
|
* @param privateKey
|
||||||
|
* @return rs in <b>asn1 format</b>
|
||||||
|
*/
|
||||||
|
public static byte[] signSm3WithSm2Asn1Rs(byte[] msg, byte[] userId, PrivateKey privateKey) {
|
||||||
|
try {
|
||||||
|
SM2ParameterSpec parameterSpec = new SM2ParameterSpec(userId);
|
||||||
|
Signature signer = BCUtils.getSignature("SM3withSM2");
|
||||||
|
// signer.setParameter(parameterSpec);
|
||||||
|
signer.initSign(privateKey, new SecureRandom());
|
||||||
|
signer.update(msg, 0, msg.length);
|
||||||
|
byte[] sig = signer.sign();
|
||||||
|
return sig;
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean verifySm3WithSm2(byte[] msg, byte[] userId, byte[] rs, byte[] publicKeyBytes) {
|
||||||
|
if (publicKeyBytes.length != 64 && publicKeyBytes.length != 65) {
|
||||||
|
throw new RuntimeException("err key length");
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger x, y;
|
||||||
|
if (publicKeyBytes.length > 64) {
|
||||||
|
x = BigIntegers.fromUnsignedByteArray(publicKeyBytes, 1, 32);
|
||||||
|
y = BigIntegers.fromUnsignedByteArray(publicKeyBytes, 33, 32);
|
||||||
|
} else {
|
||||||
|
x = BigIntegers.fromUnsignedByteArray(publicKeyBytes, 0, 32);
|
||||||
|
y = BigIntegers.fromUnsignedByteArray(publicKeyBytes, 32, 32);
|
||||||
|
}
|
||||||
|
BCECPublicKey bcecPublicKey = getPublickeyFromXY(x, y);
|
||||||
|
|
||||||
|
return verifySm3WithSm2(msg, userId, rs, bcecPublicKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param msg
|
||||||
|
* @param userId
|
||||||
|
* @param rs r||s,直接拼接byte数组的rs
|
||||||
|
* @param publicKey
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static boolean verifySm3WithSm2(byte[] msg, byte[] userId, byte[] rs, PublicKey publicKey) {
|
||||||
|
return verifySm3WithSm2Asn1Rs(msg, userId, rsPlainByteArrayToAsn1(rs), publicKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param msg
|
||||||
|
* @param userId
|
||||||
|
* @param rs in <b>asn1 format</b>
|
||||||
|
* @param publicKey
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static boolean verifySm3WithSm2Asn1Rs(byte[] msg, byte[] userId, byte[] rs, PublicKey publicKey) {
|
||||||
|
try {
|
||||||
|
|
||||||
|
Signature verifier = BCUtils.getSignature("SM3withSM2");
|
||||||
|
// verifier.setParameter(parameterSpec);
|
||||||
|
verifier.initVerify(publicKey);
|
||||||
|
verifier.update(msg, 0, msg.length);
|
||||||
|
return verifier.verify(rs);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bc加解密使用旧标c1||c2||c3,此方法在加密后调用,将结果转化为c1||c3||c2
|
||||||
|
*
|
||||||
|
* @param c1c2c3
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private static byte[] changeC1C2C3ToC1C3C2(byte[] c1c2c3) {
|
||||||
|
final int c1Len = (x9ECParameters.getCurve().getFieldSize() + 7) / 8 * 2 + 1; // sm2p256v1的这个固定65。可看GMNamedCurves、ECCurve代码。
|
||||||
|
final int c3Len = 32; // new SM3Digest().getDigestSize();
|
||||||
|
byte[] result = new byte[c1c2c3.length];
|
||||||
|
System.arraycopy(c1c2c3, 0, result, 0, c1Len); // c1
|
||||||
|
System.arraycopy(c1c2c3, c1c2c3.length - c3Len, result, c1Len, c3Len); // c3
|
||||||
|
System.arraycopy(c1c2c3, c1Len, result, c1Len + c3Len, c1c2c3.length - c1Len - c3Len); // c2
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bc加解密使用旧标c1||c3||c2,此方法在解密前调用,将密文转化为c1||c2||c3再去解密
|
||||||
|
*
|
||||||
|
* @param c1c3c2
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private static byte[] changeC1C3C2ToC1C2C3(byte[] c1c3c2) {
|
||||||
|
final int c1Len = (x9ECParameters.getCurve().getFieldSize() + 7) / 8 * 2 + 1; // sm2p256v1的这个固定65。可看GMNamedCurves、ECCurve代码。
|
||||||
|
final int c3Len = 32; // new SM3Digest().getDigestSize();
|
||||||
|
byte[] result = new byte[c1c3c2.length];
|
||||||
|
System.arraycopy(c1c3c2, 0, result, 0, c1Len); // c1: 0->65
|
||||||
|
System.arraycopy(c1c3c2, c1Len + c3Len, result, c1Len, c1c3c2.length - c1Len - c3Len); // c2
|
||||||
|
System.arraycopy(c1c3c2, c1Len, result, c1c3c2.length - c3Len, c3Len); // c3
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final static int RS_LEN = 32;
|
||||||
|
|
||||||
|
private static byte[] bigIntToFixexLengthBytes(BigInteger rOrS) {
|
||||||
|
// for sm2p256v1, n is 00fffffffeffffffffffffffffffffffff7203df6b21c6052b53bbf40939d54123,
|
||||||
|
// r and s are the result of mod n, so they should be less than n and have length<=32
|
||||||
|
byte[] rs = rOrS.toByteArray();
|
||||||
|
if (rs.length == RS_LEN) {
|
||||||
|
return rs;
|
||||||
|
} else if (rs.length == RS_LEN + 1 && rs[0] == 0) {
|
||||||
|
return Arrays.copyOfRange(rs, 1, RS_LEN + 1);
|
||||||
|
} else if (rs.length < RS_LEN) {
|
||||||
|
byte[] result = new byte[RS_LEN];
|
||||||
|
Arrays.fill(result, (byte) 0);
|
||||||
|
System.arraycopy(rs, 0, result, RS_LEN - rs.length, rs.length);
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("err rs: " + Hex.toHexString(rs));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BC的SM3withSM2签名得到的结果的rs是asn1格式的,这个方法转化成直接拼接r||s
|
||||||
|
*
|
||||||
|
* @param rsDer rs in asn1 format
|
||||||
|
* @return sign result in plain byte array
|
||||||
|
*/
|
||||||
|
private static byte[] rsAsn1ToPlainByteArray(byte[] rsDer) {
|
||||||
|
ASN1Sequence seq = ASN1Sequence.getInstance(rsDer);
|
||||||
|
byte[] r = bigIntToFixexLengthBytes(ASN1Integer.getInstance(seq.getObjectAt(0)).getValue());
|
||||||
|
byte[] s = bigIntToFixexLengthBytes(ASN1Integer.getInstance(seq.getObjectAt(1)).getValue());
|
||||||
|
byte[] result = new byte[RS_LEN * 2];
|
||||||
|
System.arraycopy(r, 0, result, 0, r.length);
|
||||||
|
System.arraycopy(s, 0, result, RS_LEN, s.length);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BC的SM3withSM2验签需要的rs是asn1格式的,这个方法将直接拼接r||s的字节数组转化成asn1格式
|
||||||
|
*
|
||||||
|
* @param sign in plain byte array
|
||||||
|
* @return rs result in asn1 format
|
||||||
|
*/
|
||||||
|
private static byte[] rsPlainByteArrayToAsn1(byte[] sign) {
|
||||||
|
if (sign.length != RS_LEN * 2) {
|
||||||
|
throw new RuntimeException("err rs. ");
|
||||||
|
}
|
||||||
|
BigInteger r = new BigInteger(1, Arrays.copyOfRange(sign, 0, RS_LEN));
|
||||||
|
BigInteger s = new BigInteger(1, Arrays.copyOfRange(sign, RS_LEN, RS_LEN * 2));
|
||||||
|
ASN1EncodableVector v = new ASN1EncodableVector();
|
||||||
|
v.add(new ASN1Integer(r));
|
||||||
|
v.add(new ASN1Integer(s));
|
||||||
|
try {
|
||||||
|
return new DERSequence(v).getEncoded("DER");
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BCECPrivateKey getPrivatekeyFromD(BigInteger d) {
|
||||||
|
ECPrivateKeySpec ecPrivateKeySpec = new ECPrivateKeySpec(d, ecParameterSpec);
|
||||||
|
return new BCECPrivateKey("EC", ecPrivateKeySpec, BouncyCastleProvider.CONFIGURATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BCECPublicKey getPublickeyFromXY(BigInteger x, BigInteger y) {
|
||||||
|
ECPublicKeySpec ecPublicKeySpec = new ECPublicKeySpec(x9ECParameters.getCurve().createPoint(x, y), ecParameterSpec);
|
||||||
|
return new BCECPublicKey("EC", ecPublicKeySpec, BouncyCastleProvider.CONFIGURATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* c1||c3||c2
|
||||||
|
*
|
||||||
|
* @param data
|
||||||
|
* @param key
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static byte[] sm2Decrypt(byte[] data, PrivateKey key) {
|
||||||
|
return sm2DecryptOld(changeC1C3C2ToC1C2C3(data), key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* c1||c3||c2
|
||||||
|
*
|
||||||
|
* @param data
|
||||||
|
* @param key
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static byte[] sm2Encrypt(byte[] data, PublicKey key) {
|
||||||
|
return changeC1C2C3ToC1C3C2(sm2EncryptOld(data, key));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* c1||c2||c3
|
||||||
|
*
|
||||||
|
* @param data
|
||||||
|
* @param key
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static byte[] sm2EncryptOld(byte[] data, PublicKey key) {
|
||||||
|
BCECPublicKey localECPublicKey = (BCECPublicKey) key;
|
||||||
|
ECPublicKeyParameters ecPublicKeyParameters = new ECPublicKeyParameters(localECPublicKey.getQ(), ecDomainParameters);
|
||||||
|
SM2Engine sm2Engine = new SM2Engine();
|
||||||
|
sm2Engine.init(true, new ParametersWithRandom(ecPublicKeyParameters, new SecureRandom()));
|
||||||
|
try {
|
||||||
|
return sm2Engine.processBlock(data, 0, data.length);
|
||||||
|
} catch (InvalidCipherTextException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* c1||c2||c3
|
||||||
|
*
|
||||||
|
* @param data
|
||||||
|
* @param key
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static byte[] sm2DecryptOld(byte[] data, PrivateKey key) {
|
||||||
|
BCECPrivateKey localECPrivateKey = (BCECPrivateKey) key;
|
||||||
|
ECPrivateKeyParameters ecPrivateKeyParameters = new ECPrivateKeyParameters(localECPrivateKey.getD(), ecDomainParameters);
|
||||||
|
SM2Engine sm2Engine = new SM2Engine();
|
||||||
|
sm2Engine.init(false, ecPrivateKeyParameters);
|
||||||
|
try {
|
||||||
|
return sm2Engine.processBlock(data, 0, data.length);
|
||||||
|
} catch (InvalidCipherTextException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] sm4Encrypt(byte[] keyBytes, byte[] plain) {
|
||||||
|
if (keyBytes.length != 16) {
|
||||||
|
throw new RuntimeException("err key length");
|
||||||
|
}
|
||||||
|
// if (plain.length % 16 != 0) throw new RuntimeException("err data length");
|
||||||
|
|
||||||
|
try {
|
||||||
|
Key key = new SecretKeySpec(keyBytes, "SM4");
|
||||||
|
|
||||||
|
Cipher out = BCUtils.getCipher("SM4/ECB/PKCS7Padding");
|
||||||
|
out.init(Cipher.ENCRYPT_MODE, key);
|
||||||
|
return out.doFinal(plain);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] sm4Decrypt(byte[] keyBytes, byte[] cipher) {
|
||||||
|
// if (keyBytes.length != 16) throw new RuntimeException("err key length");
|
||||||
|
if (cipher.length % 16 != 0) {
|
||||||
|
throw new RuntimeException("err data length");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Key key = new SecretKeySpec(keyBytes, "SM4");
|
||||||
|
Cipher in = BCUtils.getCipher("SM4/ECB/PKCS7Padding");
|
||||||
|
in.init(Cipher.DECRYPT_MODE, key);
|
||||||
|
return in.doFinal(cipher);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
byte[] msg = "1234567890".getBytes();
|
||||||
|
byte[] userId = "D91CEB11EE62219CD91CEB11EE62219C".getBytes();
|
||||||
|
byte[] prvkey = Hex.decode("5B015D0B2C0B6BEBB27EA8");
|
||||||
|
byte[] pubkey = Hex.decode("409AEFE32E150677FC2372B758178ECBAD3BBED494975596B3CD603C36F9ED7E690A5B052AFDBD86D46288FA9919BA05F3D48F6532EB28DC02D0DAA35689A50C");
|
||||||
|
|
||||||
|
prvkey = Base64.getDecoder().decode("JShsBOJL0RgPAoPttEB1hgtPAvCikOl0V1oTOYL7k5U=");
|
||||||
|
pubkey = Base64.getDecoder().decode("BE8d9gaaCGrE4dHErWCjqyahm6X8l6Rd7fOGx0gNyrGPp0XDoPbbpu1pk9A2fZ9rEsBtwB1Aecnto/gH4h+T7cY=");
|
||||||
|
byte[] asig = signSm3WithSm2(msg, userId, prvkey);
|
||||||
|
System.out.println(Hex.toHexString(asig));
|
||||||
|
boolean verified = verifySm3WithSm2(msg, userId, asig, pubkey);
|
||||||
|
System.out.println(verified);
|
||||||
|
|
||||||
|
|
||||||
|
String plainString = "1234567890abcdef";
|
||||||
|
byte[] plain = plainString.getBytes();
|
||||||
|
System.out.println(new String(plain));
|
||||||
|
// byte[] key = Hex.decode("0123456789abcdeffedcba9876543210");
|
||||||
|
byte[] sm4key = "0123456789abcdef".getBytes();
|
||||||
|
// byte[] cipher = Hex.decode("595298c7c6fd271f0402f804c33d3f66");
|
||||||
|
byte[] bs = sm4Encrypt(sm4key, plain);
|
||||||
|
System.out.println(Hex.toHexString(bs));
|
||||||
|
;
|
||||||
|
bs = sm4Decrypt(sm4key, bs);
|
||||||
|
System.out.println(new String(bs));
|
||||||
|
System.out.println(Hex.toHexString(bs));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,278 @@
|
|||||||
|
package com.dpkj.modules.chs.ynchs.utils;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.JSONArray;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import org.bouncycastle.util.encoders.Hex;
|
||||||
|
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author: muweng
|
||||||
|
* @date: 2020/1/20 21:33
|
||||||
|
* @description: 电子凭证加解密和.
|
||||||
|
*/
|
||||||
|
public class HseEncAndDecUtil {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sm2签名
|
||||||
|
*
|
||||||
|
* @param message 未加密报文
|
||||||
|
* @param sm4key 渠道sm4密钥
|
||||||
|
* @param prvKey 渠道私钥
|
||||||
|
* @return 签名串 String
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static String signature(String message, String sm4key, String prvKey) {
|
||||||
|
byte[] messageByte;
|
||||||
|
try {
|
||||||
|
JSONObject jsonObject = JSON.parseObject(message);
|
||||||
|
removeEmpty(jsonObject);
|
||||||
|
messageByte = SignUtil.getSignText(jsonObject, sm4key).getBytes("UTF-8");
|
||||||
|
} catch (Exception e) {
|
||||||
|
messageByte = message.getBytes();
|
||||||
|
}
|
||||||
|
byte[] chnlSecretByte = sm4key.getBytes();
|
||||||
|
byte[] prvkey = Base64.getDecoder().decode(prvKey);
|
||||||
|
return Base64.getEncoder().encodeToString(EasyGmUtils.signSm3WithSm2(messageByte, chnlSecretByte, prvkey));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sm2验签
|
||||||
|
*
|
||||||
|
* @param msg sm4解密后报文
|
||||||
|
* @param source 原始响应报文
|
||||||
|
* @param signData 签名串
|
||||||
|
* @param sm4key 渠道密钥
|
||||||
|
* @param pubKey 平台公钥
|
||||||
|
* @return 验证是否通过 boolean
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static boolean verify(String msg, String source, String signData, String sm4key, String pubKey) {
|
||||||
|
byte[] msgByte;
|
||||||
|
try {
|
||||||
|
JSONObject jsonObject = JSON.parseObject(msg);
|
||||||
|
JSONObject jsonObjects = JSON.parseObject(source);
|
||||||
|
jsonObjects.remove("signData");
|
||||||
|
jsonObjects.remove("encData");
|
||||||
|
jsonObjects.put("data", jsonObject);
|
||||||
|
removeEmpty(jsonObject);
|
||||||
|
String str = SignUtil.getSignText(jsonObjects, sm4key);
|
||||||
|
msgByte = str.getBytes("UTF-8");
|
||||||
|
} catch (Exception e) {
|
||||||
|
msgByte = msg.getBytes();
|
||||||
|
}
|
||||||
|
byte[] signatureByte = Base64.getDecoder().decode(signData),
|
||||||
|
chnlSecretByte = sm4key.getBytes(),
|
||||||
|
pubKeyByte = Base64.getDecoder().decode(pubKey);
|
||||||
|
return EasyGmUtils.verifySm3WithSm2(msgByte, chnlSecretByte, signatureByte, pubKeyByte);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sm4加密
|
||||||
|
*
|
||||||
|
* @param chnlId 渠道id
|
||||||
|
* @param sm4key 渠道sm4密钥
|
||||||
|
* @param message 待加密报文
|
||||||
|
* @return 加密后的报文内容 String
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static String sm4Encrypt(String chnlId, String sm4key, String message) throws Exception {
|
||||||
|
// 用appId加密appSecret获取新秘钥
|
||||||
|
byte[] appSecretEncData = EasyGmUtils.sm4Encrypt(chnlId.substring(0, 16).getBytes("UTF-8"), sm4key.getBytes("UTF-8"));
|
||||||
|
// 新秘钥串
|
||||||
|
byte[] secKey = Hex.toHexString(appSecretEncData).toUpperCase().substring(0, 16).getBytes("UTF-8");
|
||||||
|
// 加密数据
|
||||||
|
return Hex.toHexString(EasyGmUtils.sm4Encrypt(secKey, message.getBytes("UTF-8"))).toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sm4解密
|
||||||
|
*
|
||||||
|
* @param chnlId 渠道id
|
||||||
|
* @param sm4key 渠道sm4密钥
|
||||||
|
* @param message 待解密报文
|
||||||
|
* @return 解密后的报文 String
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static String sm4Decrypt(String chnlId, String sm4key, String message) throws Exception {
|
||||||
|
// 生产解密key
|
||||||
|
byte[] appSecretEncDataDecode = EasyGmUtils.sm4Encrypt(chnlId.substring(0, 16).getBytes("UTF-8"), sm4key.getBytes("UTF-8"));
|
||||||
|
byte[] secKeyDecode = Hex.toHexString(appSecretEncDataDecode).toUpperCase().substring(0, 16).getBytes("UTF-8");
|
||||||
|
return new String(EasyGmUtils.sm4Decrypt(secKeyDecode, Hex.decode(message)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private final static String version = "1.0.0";
|
||||||
|
private final static String encType = "sm4";
|
||||||
|
private final static String signType = "sm2";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建请求报文
|
||||||
|
*
|
||||||
|
* @param chnlId 渠道id
|
||||||
|
* @param encData 加密的报文
|
||||||
|
* @param signData 签名的报文
|
||||||
|
* @param transType 请求接口名
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static JSONObject buildMsg(String chnlId, String encData, String signData, String transType) {
|
||||||
|
JSONObject jsonObject = new JSONObject();
|
||||||
|
jsonObject.put("appId", chnlId);
|
||||||
|
jsonObject.put("encData", encData);
|
||||||
|
jsonObject.put("encType", encType);
|
||||||
|
jsonObject.put("signData", signData);
|
||||||
|
jsonObject.put("signType", signType);
|
||||||
|
jsonObject.put("timestamp", System.currentTimeMillis());
|
||||||
|
jsonObject.put("transType", transType);
|
||||||
|
jsonObject.put("version", version);
|
||||||
|
return jsonObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建和加密请求报文
|
||||||
|
*
|
||||||
|
* @param chnlId 渠道id
|
||||||
|
* @param sm4key 渠道sm4密钥
|
||||||
|
* @param prvkey 渠道私钥
|
||||||
|
* @param transType 请求接口名
|
||||||
|
* @param body 原始未加密的请求报文体
|
||||||
|
* @return
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static JSONObject encryptMsg(String chnlId, String sm4key, String prvkey, String transType, JSONObject body) throws Exception {
|
||||||
|
JSONObject jsonObject = new JSONObject();
|
||||||
|
jsonObject.put("appId", chnlId);
|
||||||
|
jsonObject.put("encType", encType);
|
||||||
|
jsonObject.put("data", body);
|
||||||
|
jsonObject.put("signType", signType);
|
||||||
|
jsonObject.put("timestamp", System.currentTimeMillis());
|
||||||
|
jsonObject.put("transType", transType);
|
||||||
|
jsonObject.put("version", version);
|
||||||
|
// 加密后的报文
|
||||||
|
String encData = sm4Encrypt(chnlId, sm4key, body.toJSONString());
|
||||||
|
// 签名
|
||||||
|
String signData = signature(jsonObject.toJSONString(), sm4key, prvkey);
|
||||||
|
jsonObject.fluentRemove("data");
|
||||||
|
jsonObject.put("encData", encData);
|
||||||
|
jsonObject.put("signData", signData);
|
||||||
|
return jsonObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解密报文
|
||||||
|
*
|
||||||
|
* @param jsonObject 医保电子凭证响应的原始加密报文
|
||||||
|
* @param sm4key 渠道sm4密钥
|
||||||
|
* @param pubKey 平台公钥
|
||||||
|
* @param chnlIdSrc 渠道id(兼容旧中台报文返回参数无渠道id参数情况)
|
||||||
|
* @return
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static String decryptMsg(JSONObject jsonObject, String sm4key, String pubKey, String chnlIdSrc) throws Exception {
|
||||||
|
String chnlId = (String) jsonObject.get("appId");
|
||||||
|
chnlId = StringUtil.isEmpty(chnlId) ? chnlIdSrc : chnlId;
|
||||||
|
String msg = (String) jsonObject.get("encData");
|
||||||
|
String message = (String) jsonObject.get("message");
|
||||||
|
String code = (String) jsonObject.get("code");
|
||||||
|
if (!"0".equals(code)) {
|
||||||
|
throw new RuntimeException(message);
|
||||||
|
}
|
||||||
|
// 解密
|
||||||
|
String msgS = sm4Decrypt(chnlId, sm4key, msg);
|
||||||
|
// 验签
|
||||||
|
String signData = (String) jsonObject.get("signData");
|
||||||
|
boolean flag = verify(msgS, jsonObject.toJSONString(), signData, sm4key, pubKey);
|
||||||
|
if (!flag) {
|
||||||
|
throw new RuntimeException("验签失败!!!");
|
||||||
|
}
|
||||||
|
return msgS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除json中空值的键值对
|
||||||
|
*
|
||||||
|
* @param jsonObject
|
||||||
|
*/
|
||||||
|
private static void removeEmpty(JSONObject jsonObject) {
|
||||||
|
Iterator<Map.Entry<String, Object>> it = jsonObject.entrySet().iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
Map.Entry<String, Object> entry = it.next();
|
||||||
|
Object value = entry.getValue();
|
||||||
|
if (value instanceof JSONArray) {
|
||||||
|
JSONArray jsonArray = (JSONArray) value;
|
||||||
|
// 数组长度为0时将其处理,防止Gson转换异常
|
||||||
|
if (jsonArray.size() == 0) {
|
||||||
|
it.remove();
|
||||||
|
} else {
|
||||||
|
for (Object o : jsonArray) {
|
||||||
|
JSONObject asJsonObject = (JSONObject) o;
|
||||||
|
removeEmpty(asJsonObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (value instanceof JSONObject) {
|
||||||
|
JSONObject asJsonObject = (JSONObject) value;
|
||||||
|
removeEmpty(asJsonObject);
|
||||||
|
}
|
||||||
|
if (value == null) {
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
|
if (value instanceof String && StringUtil.isEmpty(value)) {
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成sm2公私钥
|
||||||
|
*/
|
||||||
|
// System.out.println(SM2Util.getKeyPairStr());
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 渠道id
|
||||||
|
*/
|
||||||
|
String chnlId = "";
|
||||||
|
/**
|
||||||
|
* 渠道私钥
|
||||||
|
*/
|
||||||
|
String prvkey = "TcuVE2p/=";
|
||||||
|
/**
|
||||||
|
* 渠道密钥
|
||||||
|
*/
|
||||||
|
String sm4key = "";
|
||||||
|
/**
|
||||||
|
* 平台公钥
|
||||||
|
*/
|
||||||
|
String pubKey = "+++Vvnrxdp8CnkYFXBdu6c=";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 报文体
|
||||||
|
*/
|
||||||
|
JSONObject body = new JSONObject();
|
||||||
|
body.put("appUserId", "ohNH9sgKsmJC3tR_spm9jcQx_bh");
|
||||||
|
body.put("appId", chnlId);
|
||||||
|
body.put("idNo", "");
|
||||||
|
body.put("idType", "01");
|
||||||
|
body.put("userName", "");
|
||||||
|
body.put("authCode", "111111");
|
||||||
|
body.put("redirectURL", "www.baidu.com");
|
||||||
|
body.put("phone", "18050860136");
|
||||||
|
body.put("certificateStatus", "asdas");
|
||||||
|
|
||||||
|
|
||||||
|
JSONObject s1 = encryptMsg(chnlId, sm4key, prvkey, "ec.gen.link", body);
|
||||||
|
System.out.println("加密后的报文:" + s1);
|
||||||
|
|
||||||
|
String s2 = decryptMsg(s1, sm4key, pubKey, chnlId);
|
||||||
|
System.out.println("解密后的报文:" + s2);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
186
src/main/java/com/dpkj/modules/chs/ynchs/utils/SignUtil.java
Normal file
186
src/main/java/com/dpkj/modules/chs/ynchs/utils/SignUtil.java
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
package com.dpkj.modules.chs.ynchs.utils;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONArray;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import jodd.util.StringUtil;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
|
|
||||||
|
public class SignUtil {
|
||||||
|
private static List<String> ignoreSign = new ArrayList();
|
||||||
|
|
||||||
|
public static String getSignText(JSONObject jsonObject, String appSecret) {
|
||||||
|
Map<String, String> signMap = new TreeMap();
|
||||||
|
Set<Map.Entry<String, Object>> entrys = jsonObject.entrySet();
|
||||||
|
Iterator var4 = entrys.iterator();
|
||||||
|
|
||||||
|
|
||||||
|
while (var4.hasNext()) {
|
||||||
|
Map.Entry<String, Object> entry = (Map.Entry) var4.next();
|
||||||
|
if (!Optional.ofNullable(entry.getValue()).isPresent() && !ignoreSign.contains(entry.getKey())) {
|
||||||
|
signMap.put(entry.getKey(), getValue(entry.getValue()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<String> list = new ArrayList();
|
||||||
|
Iterator var10 = signMap.entrySet().iterator();
|
||||||
|
|
||||||
|
while (var10.hasNext()) {
|
||||||
|
Map.Entry<String, String> entry = (Map.Entry) var10.next();
|
||||||
|
if (StringUtil.isNotEmpty(getObjString(entry.getValue()))) {
|
||||||
|
list.add((String) entry.getKey() + "=" + (String) entry.getValue() + "&");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int size = list.size();
|
||||||
|
String[] arrayToSort = (String[]) list.toArray(new String[size]);
|
||||||
|
Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
for (int i = 0; i < size; ++i) {
|
||||||
|
sb.append(arrayToSort[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
String signText = sb.append("key=").append(appSecret).toString();
|
||||||
|
return signText;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getObjString(Object object) {
|
||||||
|
return object == null ? "" : (String) object;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getValue(Object value) {
|
||||||
|
return value instanceof String ? getObjString(value) : treeJsonParam(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String treeJsonParam(Object value) {
|
||||||
|
String jsonParam = null;
|
||||||
|
if (value instanceof Map) {
|
||||||
|
Map<String, Object> treeNestedMap = new TreeMap();
|
||||||
|
Map<?, ?> nestedMap = (Map) value;
|
||||||
|
Iterator var4 = nestedMap.entrySet().iterator();
|
||||||
|
|
||||||
|
while (var4.hasNext()) {
|
||||||
|
Map.Entry<?, ?> nestedEntry = (Map.Entry) var4.next();
|
||||||
|
treeNestedMap.put((String) nestedEntry.getKey(), nestedEntry.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonParam = JSONObject.toJSONString(treeParams(treeNestedMap));
|
||||||
|
} else if (value instanceof ArrayList) {
|
||||||
|
ArrayList<?> ar = (ArrayList) value;
|
||||||
|
jsonParam = JSONObject.toJSONString(treeList(ar));
|
||||||
|
} else if (value instanceof JSONArray) {
|
||||||
|
JSONArray jarr = (JSONArray) value;
|
||||||
|
jsonParam = JSONObject.toJSONString(treeJsonArray(jarr));
|
||||||
|
} else {
|
||||||
|
jsonParam = value.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return jsonParam;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<String, Object> treeParams(Map<String, Object> params) {
|
||||||
|
if (params == null) {
|
||||||
|
return new TreeMap();
|
||||||
|
} else {
|
||||||
|
Map<String, Object> treeParams = new TreeMap();
|
||||||
|
Iterator var2 = params.entrySet().iterator();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
while (var2.hasNext()) {
|
||||||
|
Map.Entry<String, Object> entry = (Map.Entry) var2.next();
|
||||||
|
String key = (String) entry.getKey();
|
||||||
|
Object value = entry.getValue();
|
||||||
|
if (value instanceof Map) {
|
||||||
|
Map<String, Object> treeNestedMap = new TreeMap();
|
||||||
|
Map<?, ?> nestedMap = (Map) value;
|
||||||
|
Iterator var8 = nestedMap.entrySet().iterator();
|
||||||
|
|
||||||
|
while (var8.hasNext()) {
|
||||||
|
Map.Entry<?, ?> nestedEntry = (Map.Entry) var8.next();
|
||||||
|
treeNestedMap.put((String) nestedEntry.getKey(), nestedEntry.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
treeParams.put(key, treeParams(treeNestedMap));
|
||||||
|
} else if (value instanceof ArrayList) {
|
||||||
|
ArrayList<?> ar = (ArrayList) value;
|
||||||
|
treeParams.put(key, treeList(ar));
|
||||||
|
} else if (value instanceof JSONArray) {
|
||||||
|
JSONArray ar = (JSONArray) value;
|
||||||
|
treeParams.put(key, treeJsonArray(ar));
|
||||||
|
} else if (!"".equals(value) && value != null) {
|
||||||
|
treeParams.put(key, value.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return treeParams;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static JSONArray treeList(ArrayList<?> list) {
|
||||||
|
if (list != null && list.size() != 0) {
|
||||||
|
JSONArray jsonArray = new JSONArray();
|
||||||
|
int size = list.size();
|
||||||
|
|
||||||
|
for (int i = 0; i < size; ++i) {
|
||||||
|
jsonArray.add(i, list.get(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
return treeJsonArray(jsonArray);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static JSONArray treeJsonArray(JSONArray jarr) {
|
||||||
|
if (jarr != null && jarr.size() != 0) {
|
||||||
|
JSONArray jsonArray = new JSONArray();
|
||||||
|
int size = jarr.size();
|
||||||
|
|
||||||
|
for (int i = 0; i < size; ++i) {
|
||||||
|
Object value = jarr.get(i);
|
||||||
|
if (!(value instanceof Map)) {
|
||||||
|
if (value instanceof ArrayList) {
|
||||||
|
ArrayList<?> ar = (ArrayList) value;
|
||||||
|
jsonArray.add(i, treeList(ar));
|
||||||
|
} else if (value instanceof JSONArray) {
|
||||||
|
JSONArray ar = (JSONArray) value;
|
||||||
|
jsonArray.add(i, treeJsonArray(ar));
|
||||||
|
} else if (!"".equals(value)) {
|
||||||
|
jsonArray.add(i, value.toString());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Map<String, Object> treeNestedMap = new TreeMap();
|
||||||
|
Map<?, ?> nestedMap = (Map) value;
|
||||||
|
Iterator var7 = nestedMap.entrySet().iterator();
|
||||||
|
|
||||||
|
while (var7.hasNext()) {
|
||||||
|
Map.Entry<?, ?> nestedEntry = (Map.Entry) var7.next();
|
||||||
|
treeNestedMap.put((String) nestedEntry.getKey(), nestedEntry.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonArray.add(i, treeParams(treeNestedMap));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return jsonArray;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
ignoreSign.add("signData");
|
||||||
|
ignoreSign.add("encData");
|
||||||
|
ignoreSign.add("extra");
|
||||||
|
}
|
||||||
|
}
|
||||||
430
src/main/java/com/dpkj/modules/chs/ynchs/utils/StringUtil.java
Normal file
430
src/main/java/com/dpkj/modules/chs/ynchs/utils/StringUtil.java
Normal file
@@ -0,0 +1,430 @@
|
|||||||
|
package com.dpkj.modules.chs.ynchs.utils;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.net.URLDecoder;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author: muweng
|
||||||
|
* @date: 2020/2/20 16:33
|
||||||
|
* @description: Life and death can be ignored.
|
||||||
|
*/
|
||||||
|
public final class StringUtil {
|
||||||
|
public static final int XFF00 = 65280;
|
||||||
|
public static final int XF0 = 240;
|
||||||
|
public static final int X0F = 15;
|
||||||
|
public static final int XFF = 255;
|
||||||
|
public static final int X000000FF = 255;
|
||||||
|
public static final int X0000FF00 = 65280;
|
||||||
|
public static final int SIXTEEN = 16;
|
||||||
|
public static final char[] HEX_CHARS = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
|
||||||
|
|
||||||
|
public StringUtil() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getRandomString(int length) {
|
||||||
|
String base = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||||
|
Random random = new Random();
|
||||||
|
StringBuffer sb = new StringBuffer();
|
||||||
|
|
||||||
|
for (int i = 0; i < length; ++i) {
|
||||||
|
int number = random.nextInt(base.length());
|
||||||
|
sb.append(base.charAt(number));
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getRandomNumber(int length) {
|
||||||
|
String base = "0123456789";
|
||||||
|
Random random = new Random();
|
||||||
|
StringBuffer sb = new StringBuffer();
|
||||||
|
|
||||||
|
for (int i = 0; i < length; ++i) {
|
||||||
|
int number = random.nextInt(base.length());
|
||||||
|
sb.append(base.charAt(number));
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int[] splitToIntArray(String s, String delim) {
|
||||||
|
String[] stringValueArray = split(s, delim);
|
||||||
|
int[] intValueArray = new int[stringValueArray.length];
|
||||||
|
|
||||||
|
for (int i = 0; i < intValueArray.length; ++i) {
|
||||||
|
intValueArray[i] = Integer.parseInt(stringValueArray[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return intValueArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String[] split(String source, String div) {
|
||||||
|
int arynum = 0;
|
||||||
|
int div_length = div.length();
|
||||||
|
int intIdx;
|
||||||
|
if (source.compareTo("") != 0) {
|
||||||
|
if (source.indexOf(div) != -1) {
|
||||||
|
intIdx = source.indexOf(div);
|
||||||
|
|
||||||
|
for (int var6 = 1; source.indexOf(div, intIdx + div_length) != -1; arynum = var6++) {
|
||||||
|
intIdx = source.indexOf(div, intIdx + div_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
arynum += 2;
|
||||||
|
} else {
|
||||||
|
arynum = 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
arynum = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] returnStr = new String[arynum];
|
||||||
|
if (source.compareTo("") == 0) {
|
||||||
|
return returnStr;
|
||||||
|
} else if (source.indexOf(div) == -1) {
|
||||||
|
returnStr[0] = source.substring(0, source.length());
|
||||||
|
return returnStr;
|
||||||
|
} else {
|
||||||
|
intIdx = source.indexOf(div);
|
||||||
|
returnStr[0] = source.substring(0, intIdx);
|
||||||
|
|
||||||
|
int intCount;
|
||||||
|
for (intCount = 1; source.indexOf(div, intIdx + div_length) != -1; ++intCount) {
|
||||||
|
int intIdex = source.indexOf(div, intIdx + div_length);
|
||||||
|
returnStr[intCount] = source.substring(intIdx + div_length, intIdex);
|
||||||
|
intIdx = source.indexOf(div, intIdx + div_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
returnStr[intCount] = source.substring(intIdx + div_length, source.length());
|
||||||
|
return returnStr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int doNullInt(String srcInt) {
|
||||||
|
return srcInt != null && !"".equals(srcInt) ? Integer.parseInt(srcInt) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int doNullInt(Object obj) {
|
||||||
|
String srcInt = doNullStr(obj);
|
||||||
|
return srcInt != null && !"".equals(srcInt) ? Integer.parseInt(srcInt) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long doNullLong(String srcInt) {
|
||||||
|
return srcInt != null && !"".equals(srcInt) ? Long.parseLong(srcInt) : 0L;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long doNullLong(Object obj) {
|
||||||
|
String srcInt = doNullStr(obj);
|
||||||
|
return srcInt != null && !"".equals(srcInt) ? Long.parseLong(srcInt) : 0L;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String doNullStr(Object obj) {
|
||||||
|
String str = "";
|
||||||
|
if (obj != null) {
|
||||||
|
str = String.valueOf(obj);
|
||||||
|
if (str.equals("null")) {
|
||||||
|
str = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Integer doNullInteger(Object obj) {
|
||||||
|
String str = doNullStr(obj);
|
||||||
|
if (isEmpty(str)) {
|
||||||
|
str = "0";
|
||||||
|
} else {
|
||||||
|
int i = str.indexOf(".");
|
||||||
|
if (i > 0) {
|
||||||
|
str = str.substring(0, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Integer.valueOf(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isEmpty(String[] string) {
|
||||||
|
return string == null || string.length == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isEmpty(String string) {
|
||||||
|
return string == null || "".equals(string.trim()) || "null".equals(string.trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isNotEmpty(String string) {
|
||||||
|
return !isEmpty(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isEmpty(Object o) {
|
||||||
|
return o == null || "".equals(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String padRight(String value, int totalWidth, char paddingChar) {
|
||||||
|
String temp = value;
|
||||||
|
if (value.length() > totalWidth) {
|
||||||
|
return value;
|
||||||
|
} else {
|
||||||
|
while (temp.length() < totalWidth) {
|
||||||
|
temp = temp + paddingChar;
|
||||||
|
}
|
||||||
|
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String padLeft(String value, int totalWidth, char paddingChar) {
|
||||||
|
String temp = value;
|
||||||
|
if (value.length() > totalWidth) {
|
||||||
|
return value;
|
||||||
|
} else {
|
||||||
|
while (temp.length() < totalWidth) {
|
||||||
|
temp = paddingChar + temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String reTrimByString(String value) {
|
||||||
|
String reValue;
|
||||||
|
if (value != null && !value.equals("")) {
|
||||||
|
reValue = value.trim();
|
||||||
|
} else {
|
||||||
|
reValue = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return reValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String reTrimByObject(Object obj) {
|
||||||
|
String reValue;
|
||||||
|
if (obj != null && !obj.equals("")) {
|
||||||
|
reValue = String.valueOf(obj).trim();
|
||||||
|
} else {
|
||||||
|
reValue = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return reValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int indexOfStringArray(String[] strArr, String str) {
|
||||||
|
int index = -1;
|
||||||
|
if (strArr != null && str != null) {
|
||||||
|
for (int i = 0; i < strArr.length; ++i) {
|
||||||
|
if (str.equals(strArr[i])) {
|
||||||
|
index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String replaceFirst(String whole, String strold, String strnew) {
|
||||||
|
if (whole.indexOf(strold) > -1 && strnew != null) {
|
||||||
|
String whole_one = whole.substring(0, whole.indexOf(strold));
|
||||||
|
String whole_two = whole.substring(whole.indexOf(strold) + strold.length());
|
||||||
|
whole = whole_one + strnew + whole_two;
|
||||||
|
}
|
||||||
|
|
||||||
|
return whole;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Long[] convertionToLong(String[] strs) {
|
||||||
|
Long[] longs = null;
|
||||||
|
if (!isEmpty(strs)) {
|
||||||
|
longs = new Long[strs.length];
|
||||||
|
|
||||||
|
for (int i = 0; i < strs.length; ++i) {
|
||||||
|
String str = strs[i];
|
||||||
|
long thelong = Long.valueOf(str).longValue();
|
||||||
|
longs[i] = thelong;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return longs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Long[] convertionToLongArr(String strs, String splitChar) {
|
||||||
|
if (isEmpty(splitChar)) {
|
||||||
|
splitChar = ",";
|
||||||
|
}
|
||||||
|
|
||||||
|
Long[] result = null;
|
||||||
|
if (!isEmpty(strs)) {
|
||||||
|
String[] ids = strs.split(splitChar);
|
||||||
|
result = new Long[ids.length];
|
||||||
|
|
||||||
|
for (int i = 0; i < ids.length; ++i) {
|
||||||
|
result[i] = new Long(ids[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String[] decodeStringToArray(String str, String div) {
|
||||||
|
ArrayList<String> array = new ArrayList();
|
||||||
|
StringTokenizer fenxi = new StringTokenizer(str, div);
|
||||||
|
|
||||||
|
while (fenxi.hasMoreTokens()) {
|
||||||
|
String s1 = fenxi.nextToken();
|
||||||
|
array.add(s1);
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] result = new String[array.size()];
|
||||||
|
|
||||||
|
for (int i = 0; i < result.length; ++i) {
|
||||||
|
result[i] = (String) array.get(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String convertionLongToString(Long[] l, String splitChar) {
|
||||||
|
String result = null;
|
||||||
|
if (l != null) {
|
||||||
|
result = Arrays.toString(l);
|
||||||
|
result = result.substring(1, result.length() - 1);
|
||||||
|
if (!isEmpty(splitChar)) {
|
||||||
|
result = result.replaceAll(",", splitChar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String convertionObjectArrayToStr(Object[] strings, String regx) {
|
||||||
|
String result = null;
|
||||||
|
if (regx != null) {
|
||||||
|
result = Arrays.toString(strings);
|
||||||
|
result = result.substring(1, result.length() - 1);
|
||||||
|
if (!isEmpty(regx)) {
|
||||||
|
result = result.replaceAll(",", regx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String charEncoding(String str) {
|
||||||
|
try {
|
||||||
|
str = URLDecoder.decode(str, "UTF-8");
|
||||||
|
} catch (Exception var2) {
|
||||||
|
str = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getStrTransMean(String str, String sregex, String sreplace) {
|
||||||
|
if (!isEmpty(str)) {
|
||||||
|
str = str.replaceAll(sregex, sreplace);
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String replaceSpecialChar(String s) {
|
||||||
|
return s.replaceAll("/|\\\\|\\$|#|&|%|\\*|\\^|;|,|<|>|&|'|\"", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String replaceSpecialCode(String s) {
|
||||||
|
return null != s && !"".equals(s) ? s.replaceAll("<|>|\"|%|;|\\(|\\)|&|'|\\+|\\\\", "") : s;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getMapValue(Map<String, Object> map) {
|
||||||
|
StringBuffer str = new StringBuffer();
|
||||||
|
Iterator it = map.values().iterator();
|
||||||
|
|
||||||
|
while (it.hasNext()) {
|
||||||
|
String val = String.valueOf(it.next());
|
||||||
|
str.append(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
return str.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String bSubstring(String s, int length) {
|
||||||
|
try {
|
||||||
|
byte[] bytes = s.getBytes("Unicode");
|
||||||
|
int n = 0;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i = 2; i < bytes.length && n < length; ++i) {
|
||||||
|
if (i % 2 == 1) {
|
||||||
|
++n;
|
||||||
|
} else if (bytes[i] != 0) {
|
||||||
|
++n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i % 2 == 1) {
|
||||||
|
if (bytes[i - 1] != 0) {
|
||||||
|
--i;
|
||||||
|
} else {
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new String(bytes, 0, i, "Unicode");
|
||||||
|
} catch (Exception var5) {
|
||||||
|
return new String("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getString(Object o) {
|
||||||
|
return o == null ? "" : o.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Properties getProperties(String filename) {
|
||||||
|
Properties properties = new Properties();
|
||||||
|
InputStream in = null;
|
||||||
|
in = StringUtil.class.getClassLoader().getResourceAsStream(filename);
|
||||||
|
|
||||||
|
try {
|
||||||
|
properties.load(in);
|
||||||
|
return properties;
|
||||||
|
} catch (IOException var4) {
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String dateTostr(Date date, String format) throws Exception {
|
||||||
|
SimpleDateFormat dateFormat = new SimpleDateFormat(format);
|
||||||
|
String dateStr = null;
|
||||||
|
dateStr = dateFormat.format(date);
|
||||||
|
return dateStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String iso8859ToUTF8(Object obj) {
|
||||||
|
try {
|
||||||
|
return obj == null ? "" : new String(obj.toString().getBytes("UTF-8"), "iso-8859-1");
|
||||||
|
} catch (Exception var2) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String utf8ToIso8859(Object obj) {
|
||||||
|
try {
|
||||||
|
return obj == null ? "" : new String(obj.toString().getBytes("iso-8859-1"), "UTF-8");
|
||||||
|
} catch (Exception var2) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BigDecimal getStrBigDecimal(String str) {
|
||||||
|
return isEmpty(str) ? null : new BigDecimal(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String cutString(String str, int size) {
|
||||||
|
return isNotEmpty(str) && str.length() > 100 ? str.substring(0, 100) : str;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -49,18 +49,18 @@ dpkj:
|
|||||||
# 医保机构编码
|
# 医保机构编码
|
||||||
org-id: H53082800070
|
org-id: H53082800070
|
||||||
# 收款员-编号
|
# 收款员-编号
|
||||||
operator-id: 0001
|
operator-id: 2998
|
||||||
# 收款员-姓名
|
# 收款员-姓名
|
||||||
operator-name: admin
|
operator-name: 银医自助缴费
|
||||||
# 科室-编号
|
# 科室-编号
|
||||||
office-id: 00031
|
office-id: 71
|
||||||
# 科室-名称
|
# 科室-名称
|
||||||
office-name: 门诊
|
office-name: 财务科
|
||||||
# 云南省级医保配置
|
# 云南省级医保配置
|
||||||
yn:
|
yn:
|
||||||
# 省局医保接口地址
|
# 省局医保接口地址
|
||||||
# url: http://ldjk.yn.hsip.gov.cn/eapdomain/org/local/api/hos/uldFeeInfo
|
# url: http://10.114.177.55:8080
|
||||||
url: http://ldjk.yn.hsip.gov.cn/eapdomain/callService
|
url: http://ldjk.yn.hsip.gov.cn
|
||||||
# 医保机构编码
|
# 医保机构编码
|
||||||
fixme-dins-code: H53082800070
|
fixme-dins-code: H53082800070
|
||||||
# 医保机构名称
|
# 医保机构名称
|
||||||
@@ -68,9 +68,22 @@ dpkj:
|
|||||||
# 服务商统一社会信用代码
|
# 服务商统一社会信用代码
|
||||||
info-sys-code: 9150000020285539XU
|
info-sys-code: 9150000020285539XU
|
||||||
# 服务商ID码
|
# 服务商ID码
|
||||||
|
# info-sys-sign: neu0fe98564e42458f9c86377e10e20c
|
||||||
info-sys-sign: 7f6fa92af64a403eb871a3c800cb6946
|
info-sys-sign: 7f6fa92af64a403eb871a3c800cb6946
|
||||||
# 城市编码
|
# 城市编码
|
||||||
city-code: 530800
|
city-code: 530800
|
||||||
|
# 应用ID
|
||||||
|
appid: 1IMPBSBC50OO4460C80A00001C356F13
|
||||||
|
# 应用密钥
|
||||||
|
app-key: 1IMPBSBC50OP4460C80A00004D665784
|
||||||
|
# 应用名称
|
||||||
|
app-name: 澜沧县中医医院手机自助平台
|
||||||
|
# 渠道私钥
|
||||||
|
channel-private-key: ALwGHGDcx/UEQiOYHkkym/KCjpDZGfj7AVRV3sxewJX5
|
||||||
|
# 渠道公钥
|
||||||
|
channel-public-key: BIAUk7awZVtRnd6GXqHTvTak2r3Wg6P7jWsKbBNkbSlephiS1ASWt2yFwpyWxMsqtJ59MDebkfLLDQdB/kfYxEY=
|
||||||
|
# 平台公钥
|
||||||
|
platform-public-key: BPhYoS7Bjo3MRx7I4dbtpa/dR+Na8kMY8F8yzEmlWRQjICAp0tYyfiqPt50N3NVFEijz2DJ0QY9FLCFDEdhnPvY=
|
||||||
|
|
||||||
file:
|
file:
|
||||||
# 文件保存地址
|
# 文件保存地址
|
||||||
|
|||||||
@@ -48,13 +48,17 @@ dpkj:
|
|||||||
# 云南省级医保配置
|
# 云南省级医保配置
|
||||||
yn:
|
yn:
|
||||||
# 省局医保接口地址
|
# 省局医保接口地址
|
||||||
url: http://ldjk.yn.hsip.gov.cn/eapdomain/org/local/api/hos/uldFeeInfo
|
url: http://ldjk.yn.hsip.gov.cn
|
||||||
# 医保机构编码
|
# 医保机构编码
|
||||||
fixmedins-code: H53082800070
|
fixme-dins-code: H53082800070
|
||||||
|
# 医保机构名称
|
||||||
|
fixme-dins-name: 澜沧拉祜族自治县中医医院
|
||||||
# 服务商统一社会信用代码
|
# 服务商统一社会信用代码
|
||||||
infosyscode: 9150000020285539XU
|
info-sys-code: 9150000020285539XU
|
||||||
# 服务商ID码
|
# 服务商ID码
|
||||||
infosyssign: 7f6fa92af64a403eb871a3c800cb6946
|
info-sys-sign: 7f6fa92af64a403eb871a3c800cb6946
|
||||||
|
# 城市编码
|
||||||
|
city-code: 530800
|
||||||
file:
|
file:
|
||||||
# 文件保存地址
|
# 文件保存地址
|
||||||
path: D:\Project\Express\upload
|
path: D:\Project\Express\upload
|
||||||
|
|||||||
Reference in New Issue
Block a user