省局医保

This commit is contained in:
2025-10-22 20:34:51 +08:00
parent ab32344cda
commit 71d0ae1fd8
9 changed files with 295 additions and 23 deletions

View File

@@ -22,17 +22,26 @@ public class YnChsConfig {
/** /**
* 医保机构编码 * 医保机构编码
*/ */
private String fixmedinsCode; private String fixmeDinsCode;
/**
* 医保机构名称
*/
private String fixmeDinsName;
/** /**
* 服务商统一社会信用代码 * 服务商统一社会信用代码
*/ */
private String infosyscode; private String infoSysCode;
/** /**
* 服务商ID码 * 服务商ID码
*/ */
private String infosyssign; private String infoSysSign;
/**
* 医保区划
*/
private String cityCode;
} }

View File

@@ -0,0 +1,14 @@
package com.dpkj.common.constant;
/**
* @Auther: 萧道子
* @Date: 2025/10/22 19:59
* @Description:
*/
public interface CharsetConst {
// 中文编码
String GB2312 = "GB2312";
}

View File

@@ -21,7 +21,7 @@ public class PadChsPayDll {
*/ */
public static EcDll instance() throws DllRegistrationException { public static EcDll instance() throws DllRegistrationException {
try { try {
EcDll dll = Native.load("NationECCode", EcDll.class); EcDll dll = Native.load("NationECCode.dll", EcDll.class);
// 加载动态库 // 加载动态库
/*Native.load("libeay32", EcDll.class); /*Native.load("libeay32", EcDll.class);

View File

@@ -6,6 +6,7 @@ import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference; import com.alibaba.fastjson.TypeReference;
import com.dpkj.common.config.PadChsConfig; import com.dpkj.common.config.PadChsConfig;
import com.dpkj.common.constant.CharsetConst;
import com.dpkj.common.utils.IDGenerator; import com.dpkj.common.utils.IDGenerator;
import com.dpkj.modules.chs.padchs.constant.ChsDictEnum; import com.dpkj.modules.chs.padchs.constant.ChsDictEnum;
import com.dpkj.modules.chs.padchs.constant.NationECCodeConst; import com.dpkj.modules.chs.padchs.constant.NationECCodeConst;
@@ -83,7 +84,7 @@ public class PadChsPayServiceImpl implements IPadChsPayService {
// 调用接口 // 调用接口
Pointer resp = new Memory(1024 * 10); Pointer resp = new Memory(1024 * 10);
String resultStr = dll.NationEcTrans(chsPadConfig.getUrl(), request.toString(), resp); String resultStr = dll.NationEcTrans(chsPadConfig.getUrl(), request.toString(), resp);
String response = resp.getString(0, "GB2312"); String response = resp.getString(0, CharsetConst.GB2312);
DateTime responseTime = DateUtil.date(); DateTime responseTime = DateUtil.date();
log.debug("[PadChsPayServiceImpl][getInfoByQrcode][终端医保电子凭证码解码接口] 响应:{} 出参:{}", resultStr, response); log.debug("[PadChsPayServiceImpl][getInfoByQrcode][终端医保电子凭证码解码接口] 响应:{} 出参:{}", resultStr, response);
@@ -138,7 +139,7 @@ public class PadChsPayServiceImpl implements IPadChsPayService {
// 调用接口 // 调用接口
Pointer resp = new Memory(1024 * 10); Pointer resp = new Memory(1024 * 10);
String resultStr = dll.NationEcTrans(chsPadConfig.getUrl(), request.toString(), resp); String resultStr = dll.NationEcTrans(chsPadConfig.getUrl(), request.toString(), resp);
String response = resp.getString(0, "GB2312"); String response = resp.getString(0, CharsetConst.GB2312);
DateTime responseTime = DateUtil.date(); DateTime responseTime = DateUtil.date();
log.debug("[PadChsPayServiceImpl][chsAuth][刷脸获取医保用户身份授权接口] 响应:{} 出参:{}", resultStr, response); log.debug("[PadChsPayServiceImpl][chsAuth][刷脸获取医保用户身份授权接口] 响应:{} 出参:{}", resultStr, response);
@@ -187,7 +188,7 @@ public class PadChsPayServiceImpl implements IPadChsPayService {
// 调用接口 // 调用接口
Pointer resp = new Memory(1024 * 10); Pointer resp = new Memory(1024 * 10);
String resultStr = dll.NationEcTrans(chsPadConfig.getUrl(), request.toString(), resp); String resultStr = dll.NationEcTrans(chsPadConfig.getUrl(), request.toString(), resp);
String response = resp.getString(0, "GB2312"); String response = resp.getString(0, CharsetConst.GB2312);
DateTime responseTime = DateUtil.date(); DateTime responseTime = DateUtil.date();
log.debug("[PadChsPayServiceImpl][chsCheck][刷脸授权获取医保身份接口] 响应:{} 出参:{}", resultStr, response); log.debug("[PadChsPayServiceImpl][chsCheck][刷脸授权获取医保身份接口] 响应:{} 出参:{}", resultStr, response);

View File

@@ -0,0 +1,40 @@
package com.dpkj.modules.chs.ynchs.controller;
import com.alibaba.fastjson.JSONObject;
import com.dpkj.common.vo.Result;
import com.dpkj.modules.chs.ynchs.service.IYnChsPayService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Auther: 萧道子
* @Date: 2025/10/22 16:05
* @Description:
*/
@Slf4j
@AllArgsConstructor
@RestController
@RequestMapping("/chs/yn")
public class YnChsPayController {
private final IYnChsPayService ynChsPayService;
/**
* 获取支付凭证
*
* @return com.dpkj.common.vo.Result<?>
* @author 萧道子 2025/10/22
*/
@PostMapping("getPayToken")
public Result<?> getPayToken() {
try {
JSONObject result = ynChsPayService.getPayToken();
return Result.ok("成功", result);
} catch (Exception e) {
return Result.error(e.getMessage());
}
}
}

View File

@@ -21,7 +21,8 @@ public class YnChsPayDll {
*/ */
public static EcDll instance() throws DllRegistrationException { public static EcDll instance() throws DllRegistrationException {
try { try {
return Native.load("CHSInterfaceYn", EcDll.class); // return Native.load("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);
@@ -47,16 +48,53 @@ public class YnChsPayDll {
*/ */
public interface EcDll extends Library { public interface EcDll extends Library {
/** /**
* 交易接口调用函数 * 初始化函数
* 检查整个运行环境:包括网络环境、运行所需文件、参数等的检查。
* 成功后显示医疗机构信息、服务商信息,业务经办人需要确认这些信息,避免数据造成错乱带来的损失。
* *
* @param strUrl : 业务请求地址 * @param fixmeDinsCode :
* @param InData : 交易请求数据 - JSON格式字符串 * @param infoSysCode :
* @param OutData : 交易返回数据 - code为0时交易成功否则返回错误信息说明 * @param infoSysSign :
* @return java.lang.String 返回字符串 0000 为动态库调用成功 * @param url :
* @author 萧道子 2025/7/30 * @param errMsg :
* @return int
* @author 萧道子 2025/10/22
*/ */
String NationEcTrans(String strUrl, String InData, Pointer OutData); int Init(String fixmeDinsCode, String infoSysCode, String infoSysSign, String url, Pointer errMsg);
/**
* 通用业务函数
* HIS 系统服务商需要向医保中心发送业务请求的通用函数
*
* @param fixmeDinsCode :
* @param infoSysCode :
* @param infoSysSign :
* @param inputData : 请求参数
* @param outputData : 响应结果
* @param errMsg :
* @return int
* @author 萧道子 2025/10/22
*/
int BusinessHandle(String fixmeDinsCode, String infoSysCode, String infoSysSign, String inputData, Pointer outputData, Pointer errMsg);
/**
* 通用业务函数
* HIS 系统服务商需要向医保中心发送业务请求的通用函数 输入和输出的字符集编码格式是 UTF-8
*
* @param fixmeDinsCode :
* @param infoSysCode :
* @param infoSysSign :
* @param inputData : 请求参数
* @param outputData : 响应结果
* @param errMsg :
* @return int
* @author 萧道子 2025/10/22
*/
int BusinessHandleW(String fixmeDinsCode, String infoSysCode, String infoSysSign, String inputData, Pointer outputData, Pointer errMsg);
} }

View File

@@ -1,9 +1,30 @@
package com.dpkj.modules.chs.ynchs.service; package com.dpkj.modules.chs.ynchs.service;
import com.alibaba.fastjson.JSONObject;
/** /**
* @Auther: 萧道子 * @Auther: 萧道子
* @Date: 2025/8/7 14:45 * @Date: 2025/8/7 14:45
* @Description: * @Description:
*/ */
public interface IYnChsPayService { 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();
} }

View File

@@ -1,8 +1,23 @@
package com.dpkj.modules.chs.ynchs.service.impl; 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.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.dll.YnChsPayDll;
import com.dpkj.modules.chs.ynchs.service.IYnChsPayService; import com.dpkj.modules.chs.ynchs.service.IYnChsPayService;
import com.sun.jna.Memory;
import com.sun.jna.Pointer;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@@ -22,6 +37,8 @@ public class YnChsPayServiceImpl implements IYnChsPayService {
@Autowired @Autowired
private YnChsConfig ynChsConfig; private YnChsConfig ynChsConfig;
@Autowired
private IPadChsPayService padChsPayService;
@PostConstruct @PostConstruct
public void postConstruct() { public void postConstruct() {
@@ -32,11 +49,137 @@ public class YnChsPayServiceImpl implements IYnChsPayService {
log.error("[YnChsPayServiceImpl][postConstruct][云南省局医保DLL] 加载失败:{}", e.getMessage()); log.error("[YnChsPayServiceImpl][postConstruct][云南省局医保DLL] 加载失败:{}", e.getMessage());
throw new RuntimeException("云南省局医保DLL库加载失败" + e.getMessage(), e); throw new RuntimeException("云南省局医保DLL库加载失败" + e.getMessage(), e);
} }
initPrinter();
} }
private void initPrinter() { @Override
// TODO 萧道子 2025/7/31 : 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);
}
}
}

View File

@@ -1,5 +1,5 @@
server: server:
port: 15948 port: 15946
servlet: servlet:
context-path: /api context-path: /api
tomcat: tomcat:
@@ -59,13 +59,19 @@ dpkj:
# 云南省级医保配置 # 云南省级医保配置
yn: yn:
# 省局医保接口地址 # 省局医保接口地址
url: http://ldjk.yn.hsip.gov.cn/eapdomain/org/local/api/hos/uldFeeInfo # url: http://ldjk.yn.hsip.gov.cn/eapdomain/org/local/api/hos/uldFeeInfo
url: http://ldjk.yn.hsip.gov.cn/eapdomain/callService
# 医保机构编码 # 医保机构编码
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: G:\Temp\img path: G:\Temp\img