BankUtil.java 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. package com.hcloud.microserver.bank.util;
  2. import com.alibaba.fastjson.JSONObject;
  3. import com.hcloud.microserver.bank.bo.BankLoginUserRespBO;
  4. import com.hcloud.microserver.bank.bo.BankQueryBaseParam;
  5. import com.hcloud.microserver.bank.bo.BankResponseBase;
  6. import com.hcloud.microserver.commoncore.util.string.StringUtils;
  7. import lombok.Data;
  8. import lombok.extern.slf4j.Slf4j;
  9. import org.apache.commons.httpclient.HttpClient;
  10. import org.apache.commons.httpclient.HttpStatus;
  11. import org.apache.commons.httpclient.methods.PostMethod;
  12. import org.dom4j.DocumentException;
  13. import org.springframework.beans.factory.annotation.Autowired;
  14. import org.springframework.beans.factory.annotation.Value;
  15. import org.springframework.data.redis.core.RedisTemplate;
  16. import org.springframework.data.redis.core.ValueOperations;
  17. import org.springframework.stereotype.Component;
  18. import java.io.*;
  19. import java.net.Socket;
  20. import java.text.SimpleDateFormat;
  21. import java.util.Date;
  22. import java.util.HashMap;
  23. import java.util.Map;
  24. import java.util.concurrent.TimeUnit;
  25. import java.util.regex.Matcher;
  26. import java.util.regex.Pattern;
  27. @Slf4j
  28. @Data
  29. @Component
  30. public class BankUtil {
  31. private final static SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
  32. private String charset="gb2312";
  33. @Value("${cqrcb.bank.sign.ip}")
  34. private String ipSign;
  35. @Value("${cqrcb.bank.sign.port}")
  36. private int portSign;
  37. @Value("${cqrcb.bank.sslclient.ip}")
  38. private String ip;
  39. @Value("${cqrcb.bank.sslclient.port}")
  40. private int port;
  41. @Autowired
  42. private RedisTemplate redisTemplate;
  43. /**
  44. * 根据传入实体进行业务接口对接
  45. * @param param
  46. * @param type 0 为不签名 1 为签名
  47. * @param clazz
  48. * @return
  49. */
  50. public BankResponseBase bankRequst(BankQueryBaseParam param, int type,Class<? extends BankResponseBase> clazz) {
  51. if (param==null||param.getData()==null){
  52. return null;
  53. }
  54. Object paramData = param.getData();
  55. Map<String,Object> reqParam= new HashMap<>();
  56. reqParam.put("ReqParam",paramData);
  57. Map<String,Object> opReq = new HashMap<>();
  58. opReq.put("opReq",reqParam);
  59. Map<String,Object> CQRCBBankData = new HashMap<>();
  60. CQRCBBankData.put("CQRCBBankData",opReq);
  61. try {
  62. if (type ==1){
  63. String s = packSignXml(paramData);
  64. opReq.put("signData",s);
  65. }
  66. Object o = JSONObject.toJSON(CQRCBBankData);
  67. RemoveNullAttr re = new RemoveNullAttr();
  68. Object o1 = re.traverseJson(o);
  69. String s = JsonAndXmlUtils.jsonToPrettyXml((JSONObject)o1);
  70. String url1 = "http://"+ip+":"+port+"/corporLink";
  71. String h = param.getSessionId()+"|"+param.getServiceId()+"|"+param.getSerialNo()+"|"+param.getReqTime()+"|#";
  72. log.info("request cqcrb url:"+url1);
  73. log.info(param.getServiceId()+" request cqcrb content:"+h+s);
  74. String resp = sendPost(url1, h + s);
  75. log.info("cqcrb response content:"+resp);
  76. return xmlStringToEntity(resp,clazz);
  77. // return resp;
  78. }catch (Exception e){
  79. log.info("fail to request "+param.getServiceId()+"{}",paramData);
  80. }
  81. return null;
  82. }
  83. /**
  84. * 解析xml文件维对应的实体
  85. * @param xmlString
  86. * @param clazz
  87. * @return
  88. */
  89. public BankResponseBase xmlStringToEntity(String xmlString,Class<? extends BankResponseBase> clazz) throws Exception {
  90. if (StringUtils.isEmpty(xmlString)){
  91. return null;
  92. }
  93. String [] split;
  94. if (xmlString.contains("|#")){
  95. String name = clazz.getName();
  96. BankResponseBase responseBase = clazz.newInstance();
  97. String headString = xmlString.substring(0, xmlString.lastIndexOf("|#"));
  98. String xml = xmlString.substring(xmlString.lastIndexOf("|#")+2);
  99. split = headString.split("\\|");
  100. int length = split.length;
  101. if (length <3){
  102. return null;
  103. }
  104. JSONObject jsonObject = JsonAndXmlUtils.xmlToJson(xml);
  105. log.info(xml);
  106. if (jsonObject.containsKey("CQRCBBankData")){
  107. JSONObject CQRCBBankDataJSON = (JSONObject) jsonObject.get("CQRCBBankData");
  108. if (CQRCBBankDataJSON.containsKey("opRep")){
  109. JSONObject opRepJSON = (JSONObject) CQRCBBankDataJSON.get("opRep");
  110. if (opRepJSON.containsKey("opResult")){
  111. Object opResultObject = opRepJSON.get("opResult");
  112. // net.sf.json.JSONObject jsonObject1 = net.sf.json.JSONObject.fromObject(opResultObject);
  113. // responseBase = (BankResponseBase) net.sf.json.JSONObject.toBean(jsonObject1, clazz);
  114. responseBase = JSONObject.parseObject(JSONObject.toJSONString(opResultObject), clazz);
  115. responseBase.setSessionId(split[0]);
  116. responseBase.setSerialNo(split[1]);
  117. responseBase.setRetCode(split[2]);
  118. if (length > 3){
  119. responseBase.setErrorMsg(split[3]);
  120. }
  121. }
  122. }
  123. }
  124. return responseBase;
  125. }
  126. return null;
  127. }
  128. /**
  129. * 发送xml请求到server端
  130. * @param url xml请求数据地址
  131. * @param xmlString 发送的xml数据流
  132. * @return null发送失败,否则返回响应内容
  133. */
  134. public String sendPost(String url,String xmlString){
  135. //创建httpclient工具对象
  136. HttpClient client = new HttpClient();
  137. //创建post请求方法
  138. PostMethod myPost = new PostMethod(url);
  139. //设置请求超时时间
  140. // client.setConnectionTimeout(3000*1000);
  141. String responseString = null;
  142. try{
  143. //设置请求头部类型
  144. myPost.setRequestHeader("Content-Type","text/xml;charset=utf-8");
  145. //设置请求体,即xml文本内容,一种是直接获取xml内容字符串,一种是读取xml文件以流的形式
  146. myPost.setRequestBody(xmlString);
  147. int statusCode = client.executeMethod(myPost);
  148. //只有请求成功200了,才做处理
  149. if(statusCode == HttpStatus.SC_OK){
  150. InputStream inputStream = myPost.getResponseBodyAsStream();
  151. // BufferedReader br = new BufferedReader(new InputStreamReader(inputStream,"UTF-8"));
  152. // StringBuffer stringBuffer = new StringBuffer();
  153. // String str = "";
  154. // while ((str = br.readLine()) != null) {
  155. // stringBuffer.append(str);
  156. // }
  157. // responseString = stringBuffer.toString();
  158. responseString = convertStreamToString(inputStream);
  159. }
  160. }catch (Exception e) {
  161. e.printStackTrace();
  162. }finally{
  163. myPost.releaseConnection();
  164. }
  165. return responseString;
  166. }
  167. public String convertStreamToString(InputStream is) {
  168. StringBuilder sb1 = new StringBuilder();
  169. byte[] bytes = new byte[4096];
  170. int size = 0;
  171. try {
  172. while ((size = is.read(bytes)) > 0) {
  173. String str = new String(bytes, 0, size, "UTF-8");
  174. sb1.append(str);
  175. }
  176. } catch (IOException e) {
  177. e.printStackTrace();
  178. } finally {
  179. try {
  180. is.close();
  181. } catch (IOException e) {
  182. e.printStackTrace();
  183. }
  184. }
  185. return sb1.toString();
  186. }
  187. /**
  188. * 1. sessionId为会话编号,每次登录之后会产生一个唯一的编号,用于标识这次会话。用户每次进行交易时都必须上送该Id。如果是登录交易,则请求报文头中的sessionId传-1即可。
  189. * 2. serviceId为服务编号,用以区分不同的操作,见具体交易格式说明,如登录交易的服务编号为: CL0001。
  190. * 3. serialNo为交易序列号,客户端唯一标识,返回时原样返回。
  191. * 4. reqTime为请求时间,yyyyMMddHHmmss。
  192. * 5. retCode和errorMsg为响应代码和错误信息,请求处理成功时,返回代码为’00000000’,错误信息留空;其它情况均视为请求处理失败。
  193. * 6. 请求报文体和响应报文体为XML格式,封装了具体的交易数据,格式请参见下一章节描述。
  194. * 7. 对于登录和转账等交易,请求报文体需要进行签名。
  195. * 8. 登录后,企业客户如果在设定时间之内没有进行任何请求,该会话将被自动清理,需要重新登录后才可以进行一般交易请求。(目前暂定:设置超时时间为12小时)
  196. * 9. 如果sessionId对应的会话是超时或者非法的时候,服务端只会返回响应报文头“-1|EBLN0000|会话已超时,请重新登录|#”,不会返回报文体。
  197. * 10. 如果请求的XML包格式不正确,或者opName指定的交易名称不正确时,服务器端也只会返回响应报文头,不会返回报文体。
  198. * @param sessionId
  199. * @param serviceId
  200. * @return
  201. */
  202. public String getRequestUrl(String ip,int port,String sessionId,String serviceId,String serialNo){
  203. String url = "http://"+ip+":"+port;
  204. return url;
  205. }
  206. public String getTime(Date date){
  207. return format.format(date);
  208. }
  209. public String sendSignRequestTCP(String oriData) {
  210. StringBuffer sb = new StringBuffer("");
  211. Socket socket = null;
  212. BufferedInputStream in = null;
  213. BufferedOutputStream out = null;
  214. log.info("sign ip:"+ipSign);
  215. log.info("sign port:"+portSign);
  216. log.info("sign content:"+oriData);
  217. try {
  218. int length = oriData.getBytes(charset).length;
  219. byte[] buf = new byte[length + 5];
  220. String lenValue = String.valueOf(length);
  221. System.arraycopy(oriData.getBytes(charset), 0, buf, 5, length);
  222. for (int i = 0; i < 5; i++)
  223. buf[i] = '0';
  224. int idx = 0;
  225. for (int i = 5 - lenValue.length(); i < 5; i++) {
  226. buf[i] = (byte) lenValue.charAt(idx++);
  227. }
  228. socket = new Socket(ipSign, portSign);
  229. out = new BufferedOutputStream(socket.getOutputStream());
  230. out.write(buf);
  231. out.flush();
  232. in = new BufferedInputStream(socket.getInputStream());
  233. byte[] buffer = new byte[1024];
  234. int len = 0;
  235. while ((len = in.read(buffer)) != -1) {
  236. sb.append(new String(buffer, 0, len, charset));
  237. }
  238. } catch (Exception e) {
  239. sb = new StringBuffer("-1");
  240. e.printStackTrace();
  241. } finally {
  242. try {
  243. if (null != socket) {
  244. socket.close();
  245. }
  246. } catch (Exception e) {
  247. e.printStackTrace();
  248. }
  249. try {
  250. if (out != null)
  251. out.close();
  252. } catch (Exception e) {
  253. e.printStackTrace();
  254. }
  255. try {
  256. if (in != null)
  257. in.close();
  258. } catch (Exception e) {
  259. e.printStackTrace();
  260. }
  261. }
  262. return sb.toString();
  263. }
  264. /**
  265. * <msg>
  266. * <msg_head>
  267. * <msg_type>0</msg_type>
  268. * <msg_id>1005</msg_id>
  269. * <msg_sn>0</msg_sn>
  270. * <version>1</version>
  271. * </msg_head>
  272. * <msg_body>
  273. * <origin_data_len>签名原文的长度</origin_data_len>
  274. * <origin_data>签名原文</origin_data>
  275. * </msg_body>
  276. * </msg>
  277. * @param paramData
  278. * @return
  279. */
  280. public String packSignXml(Object paramData) throws Exception {
  281. if (paramData == null){
  282. return null;
  283. }
  284. JSONObject si = new JSONObject();
  285. si.put("ReqParam",JSONObject.toJSON(paramData));
  286. String sJson = JsonAndXmlUtils.JsonToXml((JSONObject) JSONObject.parse(JSONObject.toJSONString(si)));
  287. String substring = sJson.substring(sJson.lastIndexOf("<ReqParam>"));
  288. log.info("签名后的数据:"+substring);
  289. JSONObject head =new JSONObject();
  290. head.put("msg_type",0);
  291. head.put("msg_id",1005);
  292. head.put("msg_sn",0);
  293. head.put("version",1);
  294. JSONObject body = new JSONObject();
  295. body.put("origin_data_len",substring.length());
  296. body.put("origin_data","dataDataJxml");
  297. JSONObject msg = new JSONObject();
  298. msg.put("msg_head",head);
  299. msg.put("msg_body",body);
  300. JSONObject req = new JSONObject();
  301. req.put("msg",msg);
  302. String s = JsonAndXmlUtils.JsonToXml(req);
  303. String dataDataJxml = s.replace("dataDataJxml", substring);
  304. String s1 = sendSignRequestTCP(dataDataJxml);
  305. String s2 = xmlToSignData(s1);
  306. log.info("sign return data :"+s1);
  307. log.info("data sign content :"+s2);
  308. return s2;
  309. }
  310. public String xmlToSignData(String xmlString) throws DocumentException {
  311. JSONObject jsonObject = JsonAndXmlUtils.xmlToJson(xmlString);
  312. if (jsonObject.containsKey("msg")){
  313. JSONObject msg = (JSONObject)jsonObject.get("msg");
  314. if (msg.containsKey("msg_body")){
  315. JSONObject msg_body = (JSONObject)msg.get("msg_body");
  316. if (msg_body.containsKey("signed_data")){
  317. String signed_data = msg_body.get("signed_data").toString();
  318. return replaceBlank(signed_data);
  319. }
  320. }
  321. }
  322. return null;
  323. }
  324. public String replaceBlank(String str) {
  325. String dest = "";
  326. if (str!=null) {
  327. Pattern p = Pattern.compile("\\s*|\t|\r|\n");
  328. Matcher m = p.matcher(str);
  329. dest = m.replaceAll("");
  330. }
  331. return dest;
  332. }
  333. public void cacheLoginSession(BankLoginUserRespBO bankLoginUserRespBO){
  334. ValueOperations ops = redisTemplate.opsForValue();
  335. ops.set("cqcarbon.bank.user.sessionId",bankLoginUserRespBO,12*3600, TimeUnit.SECONDS);
  336. }
  337. public BankLoginUserRespBO getLoginSession(){
  338. ValueOperations ops = redisTemplate.opsForValue();
  339. BankLoginUserRespBO o = (BankLoginUserRespBO)ops.get("cqcarbon.bank.user.sessionId");
  340. if (o != null){
  341. return o;
  342. }
  343. return null;
  344. }
  345. }