ExecService.java 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. package thyyxxk.webserver.service.medicalinsurance;
  2. import cn.hutool.core.util.StrUtil;
  3. import com.alibaba.fastjson.JSONObject;
  4. import lombok.extern.slf4j.Slf4j;
  5. import org.apache.commons.codec.binary.Base64;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.http.HttpEntity;
  8. import org.springframework.http.HttpHeaders;
  9. import org.springframework.stereotype.Service;
  10. import org.springframework.web.client.RestTemplate;
  11. import thyyxxk.webserver.config.envionment.MedinsurConfig;
  12. import thyyxxk.webserver.config.exception.BizException;
  13. import thyyxxk.webserver.constants.sidicts.SiFunction;
  14. import thyyxxk.webserver.dao.his.medicalinsurance.SiZyDao;
  15. import thyyxxk.webserver.utils.DateUtil;
  16. import thyyxxk.webserver.utils.StringUtil;
  17. import thyyxxk.webserver.utils.TokenUtil;
  18. import javax.crypto.Mac;
  19. import javax.crypto.spec.SecretKeySpec;
  20. import java.text.SimpleDateFormat;
  21. import java.util.Date;
  22. import java.util.HashMap;
  23. import java.util.Map;
  24. /**
  25. * @description: 医保交易执行
  26. * @author: DingJie
  27. * @create: 2021-05-28 15:57:26
  28. **/
  29. @Slf4j
  30. @Service
  31. public class ExecService {
  32. private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
  33. private static final String RESULT_CODE = "infcode";
  34. private static final String OUTPUT = "output";
  35. private static int serial = 1000;
  36. private static final int MIN_VAL = 1000;
  37. private static final int MAX_VAL = 9999;
  38. private volatile String signNo;
  39. private final SiZyDao dao;
  40. private final RestTemplate template;
  41. private final MedinsurConfig cfg;
  42. @Autowired
  43. public ExecService(SiZyDao dao, RestTemplate template, MedinsurConfig cfg) {
  44. this.dao = dao;
  45. this.template = template;
  46. this.cfg = cfg;
  47. }
  48. public synchronized String makeMsgId() {
  49. serial += 1;
  50. if (serial > MAX_VAL) {
  51. serial = MIN_VAL;
  52. }
  53. return cfg.getHospId() + sdf.format(new Date()) + serial;
  54. }
  55. private synchronized String getSignNo() {
  56. if (StringUtil.isBlank(signNo)) {
  57. signIn();
  58. }
  59. return signNo;
  60. }
  61. public synchronized void signIn() {
  62. String dbSignNo = dao.getSignInNo();
  63. if (StrUtil.isNotBlank(dbSignNo)) {
  64. signNo = dbSignNo;
  65. log.info("获取历史签到号成功:{}", dbSignNo);
  66. return;
  67. }
  68. JSONObject input = makeSignHeader(SiFunction.SIGN_IN);
  69. JSONObject signIn = new JSONObject();
  70. signIn.put("opter_no", "99999");
  71. signIn.put("mac", cfg.getMacAddress());
  72. signIn.put("ip", cfg.getIpAddress());
  73. input.getJSONObject("input").put("signIn", signIn);
  74. JSONObject result = executeTrade(input, SiFunction.SIGN_IN);
  75. if (null != result && result.getInteger(RESULT_CODE) == 0) {
  76. try {
  77. JSONObject output = result.getJSONObject(OUTPUT);
  78. signNo = output.getJSONObject("signinoutb").getString("sign_no");
  79. dao.updateSignNo(signNo);
  80. log.info("签到成功,签到号:{}", signNo);
  81. } catch (Exception e) {
  82. throw new BizException();
  83. }
  84. }
  85. }
  86. public void signOut() {
  87. if (StringUtil.notBlank(signNo)) {
  88. JSONObject input = makeSignHeader(SiFunction.SIGN_OUT);
  89. JSONObject signOut = new JSONObject();
  90. signOut.put("sign_no", signNo);
  91. signOut.put("opter_no", "99999");
  92. input.getJSONObject("input").put("signOut", signOut);
  93. JSONObject result = executeTrade(input, SiFunction.SIGN_OUT);
  94. if (null != result && result.getIntValue(RESULT_CODE) == 0) {
  95. log.info("医保签退成功。");
  96. signNo = null;
  97. dao.updateSignNo(signNo);
  98. }
  99. }
  100. }
  101. public String getInstitutionArea(String insureArea) {
  102. String hospArea = cfg.getHospArea();
  103. String prefix = hospArea.substring(0, 4);
  104. return insureArea.startsWith(prefix) ? hospArea : prefix.substring(0, 2) + "9900";
  105. }
  106. private JSONObject makeSignHeader(SiFunction function) {
  107. JSONObject header = makePublicHeader("");
  108. header.put("infno", function.getCode());
  109. header.put("opter", "99999");
  110. header.put("opter_name", "全院");
  111. return header;
  112. }
  113. public JSONObject makeTradeHeader(SiFunction function) {
  114. String staffId = TokenUtil.getInstance().getTokenUserId();
  115. String staffName = dao.selectStaffName(staffId);
  116. JSONObject header = makePublicHeader(cfg.getHospArea());
  117. header.put("infno", function.getCode());
  118. header.put("opter", staffId);
  119. header.put("opter_name", staffName);
  120. header.replace("sign_no", getSignNo());
  121. return header;
  122. }
  123. public JSONObject makeTradeHeaderWithInsureArea(SiFunction function, String insureArea) {
  124. String staffId = TokenUtil.getInstance().getTokenUserId();
  125. String staffName = dao.selectStaffName(staffId);
  126. JSONObject header = makePublicHeader(insureArea);
  127. header.put("infno", function.getCode());
  128. header.put("opter", staffId);
  129. header.put("opter_name", staffName);
  130. header.replace("sign_no", getSignNo());
  131. return header;
  132. }
  133. private JSONObject makePublicHeader(String insureArea) {
  134. if (null == insureArea) {
  135. insureArea = "";
  136. }
  137. JSONObject header = new JSONObject();
  138. JSONObject input = new JSONObject();
  139. header.put("msgid", makeMsgId());
  140. header.put("mdtrtarea_admvs", getInstitutionArea(insureArea));
  141. header.put("insuplc_admdvs", insureArea);
  142. header.put("recer_sys_code", "医院");
  143. header.put("dev_no", "");
  144. header.put("dev_safe_info", "");
  145. header.put("cainfo", "");
  146. header.put("signtype", "");
  147. header.put("infver", cfg.getApiVersion());
  148. header.put("opter_type", "1");
  149. header.put("inf_time", DateUtil.now());
  150. header.put("fixmedins_code", cfg.getHospId());
  151. header.put("fixmedins_name", cfg.getHospName());
  152. header.put("sign_no", "");
  153. if (StrUtil.isNotBlank(cfg.getSoftDeveloper())) {
  154. header.put("fixmedins_soft_fcty", cfg.getSoftDeveloper());
  155. }
  156. header.put("input", input);
  157. return header;
  158. }
  159. public Map<String, String> getSiHeaderMap(SiFunction function) {
  160. Map<String, String> headers = new HashMap<>();
  161. String timestamp = String.valueOf(System.currentTimeMillis());
  162. String signature = getSignature(timestamp, function.getCode());
  163. // 医保原始地址添加header
  164. // headers.put("_api_access_key", apiAccessKey);
  165. // headers.put("_api_secreKey", apiSecretKey);
  166. // headers.put("_api_name", function.getCode());
  167. // headers.put("_api_version", API_VERSION);
  168. // headers.put("_api_timestamp", timestamp);
  169. // headers.put("_api_signature", signature);
  170. // webhis.thyy.cn代理地址添加header
  171. headers.put("apiAccessKey", cfg.getAccessKey());
  172. headers.put("apiSecreKey", cfg.getSecretKey());
  173. headers.put("apiName", StrUtil.isBlank(cfg.getApiName()) ? function.getCode() : cfg.getApiName());
  174. headers.put("apiVersion", cfg.getApiVersion());
  175. headers.put("apiTimestamp", timestamp);
  176. headers.put("apiSignature", signature);
  177. return headers;
  178. }
  179. public HttpHeaders getHttpHeaders(SiFunction function) {
  180. String timestamp = String.valueOf(System.currentTimeMillis());
  181. String signature = getSignature(timestamp, function.getCode());
  182. HttpHeaders headers = new HttpHeaders();
  183. headers.add("apiAccessKey", cfg.getAccessKey());
  184. headers.add("apiSecreKey", cfg.getSecretKey());
  185. headers.add("apiName", StrUtil.isBlank(cfg.getApiName()) ? function.getCode() : cfg.getApiName());
  186. headers.add("apiVersion", cfg.getApiVersion());
  187. headers.add("apiTimestamp", timestamp);
  188. headers.add("apiSignature", signature);
  189. return headers;
  190. }
  191. public String getSignature(String timestamp, String function) {
  192. String source =
  193. "_api_access_key=" + cfg.getAccessKey() +
  194. "&_api_name=" + function +
  195. "&_api_timestamp=" + timestamp +
  196. "&_api_version=" + cfg.getApiVersion();
  197. return hmacSha1(source);
  198. }
  199. private String hmacSha1(String src) {
  200. byte[] result = null;
  201. try {
  202. SecretKeySpec signInKey = new SecretKeySpec(cfg.getSecretKey().getBytes(), "HmacSHA1");
  203. Mac mac = Mac.getInstance("HmacSHA1");
  204. mac.init(signInKey);
  205. byte[] rawHmac = mac.doFinal(src.getBytes());
  206. result = Base64.encodeBase64(rawHmac);
  207. } catch (Exception e) {
  208. log.error("HmacSHA1加密出错", e);
  209. }
  210. return null == result ? null : new String(result);
  211. }
  212. public JSONObject executeTrade(JSONObject input, SiFunction function) {
  213. try {
  214. log.info("医保接口调用:【接口号:" + function.getCode() +
  215. ",接口名:" + function.getName() +
  216. ",操作员:" + input.getString("opter_name"));
  217. String result = template.postForObject(cfg.getApiUrl(),
  218. new HttpEntity<>(input, getHttpHeaders(function)), String.class);
  219. log.info("医保接口调用:返回:" + result);
  220. return JSONObject.parseObject(result);
  221. } catch (Exception e) {
  222. log.error("医保网络出错", e);
  223. JSONObject object = new JSONObject();
  224. object.put("infcode", -1);
  225. if (e.getMessage().contains("Connection timed out")) {
  226. object.put("err_msg", "医保中心网络故障,连接超时。");
  227. } else {
  228. object.put("err_msg", e.getMessage());
  229. }
  230. return object;
  231. }
  232. }
  233. /**
  234. * 工伤接口URL
  235. */
  236. // 模拟接口地址(当前使用)
  237. private static final String WORK_INJURY_API_URL = "http://130.150.161.72:9206/thyy/api/public/injury/workinjury";
  238. // 真实接口地址(注释掉,需要时手动切换)
  239. // private static final String WORK_INJURY_API_URL = "http://localhost:8321/api/entry/workinjury";
  240. /**
  241. * 执行工伤接口调用(工伤接口使用不同的请求头格式)
  242. */
  243. public JSONObject executeWorkInjuryTrade(JSONObject input) {
  244. HttpHeaders headers = new HttpHeaders();
  245. headers.add("Content-Type", "application/json");
  246. // 工伤接口可能不需要医保接口的认证头,直接使用简单的JSON头
  247. return template.postForObject(WORK_INJURY_API_URL,
  248. new HttpEntity<>(input, headers), JSONObject.class);
  249. }
  250. }