package com.hcloud.microserver.bank.util; import com.alibaba.fastjson.JSONObject; import com.hcloud.microserver.bank.bo.BankLoginUserRespBO; import com.hcloud.microserver.bank.bo.BankQueryBaseParam; import com.hcloud.microserver.bank.bo.BankResponseBase; import com.hcloud.microserver.commoncore.util.string.StringUtils; import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.methods.PostMethod; import org.dom4j.DocumentException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.ValueOperations; import org.springframework.stereotype.Component; import java.io.*; import java.net.Socket; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; @Slf4j @Data @Component public class BankUtil { private final static SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss"); private String charset="gb2312"; @Value("${cqrcb.bank.sign.ip}") private String ipSign; @Value("${cqrcb.bank.sign.port}") private int portSign; @Value("${cqrcb.bank.sslclient.ip}") private String ip; @Value("${cqrcb.bank.sslclient.port}") private int port; @Autowired private RedisTemplate redisTemplate; /** * 根据传入实体进行业务接口对接 * @param param * @param type 0 为不签名 1 为签名 * @param clazz * @return */ public BankResponseBase bankRequst(BankQueryBaseParam param, int type,Class clazz) { if (param==null||param.getData()==null){ return null; } Object paramData = param.getData(); Map reqParam= new HashMap<>(); reqParam.put("ReqParam",paramData); Map opReq = new HashMap<>(); opReq.put("opReq",reqParam); Map CQRCBBankData = new HashMap<>(); CQRCBBankData.put("CQRCBBankData",opReq); try { if (type ==1){ String s = packSignXml(paramData); opReq.put("signData",s); } Object o = JSONObject.toJSON(CQRCBBankData); RemoveNullAttr re = new RemoveNullAttr(); Object o1 = re.traverseJson(o); String s = JsonAndXmlUtils.jsonToPrettyXml((JSONObject)o1); String url1 = "http://"+ip+":"+port+"/corporLink"; String h = param.getSessionId()+"|"+param.getServiceId()+"|"+param.getSerialNo()+"|"+param.getReqTime()+"|#"; log.info("request cqcrb url:"+url1); log.info(param.getServiceId()+" request cqcrb content:"+h+s); String resp = sendPost(url1, h + s); log.info("cqcrb response content:"+resp); return xmlStringToEntity(resp,clazz); // return resp; }catch (Exception e){ log.info("fail to request "+param.getServiceId()+"{}",paramData); } return null; } /** * 解析xml文件维对应的实体 * @param xmlString * @param clazz * @return */ public BankResponseBase xmlStringToEntity(String xmlString,Class clazz) throws Exception { if (StringUtils.isEmpty(xmlString)){ return null; } String [] split; if (xmlString.contains("|#")){ String name = clazz.getName(); BankResponseBase responseBase = clazz.newInstance(); String headString = xmlString.substring(0, xmlString.lastIndexOf("|#")); String xml = xmlString.substring(xmlString.lastIndexOf("|#")+2); split = headString.split("\\|"); int length = split.length; if (length <3){ return null; } JSONObject jsonObject = JsonAndXmlUtils.xmlToJson(xml); log.info(xml); if (jsonObject.containsKey("CQRCBBankData")){ JSONObject CQRCBBankDataJSON = (JSONObject) jsonObject.get("CQRCBBankData"); if (CQRCBBankDataJSON.containsKey("opRep")){ JSONObject opRepJSON = (JSONObject) CQRCBBankDataJSON.get("opRep"); if (opRepJSON.containsKey("opResult")){ Object opResultObject = opRepJSON.get("opResult"); // net.sf.json.JSONObject jsonObject1 = net.sf.json.JSONObject.fromObject(opResultObject); // responseBase = (BankResponseBase) net.sf.json.JSONObject.toBean(jsonObject1, clazz); responseBase = JSONObject.parseObject(JSONObject.toJSONString(opResultObject), clazz); responseBase.setSessionId(split[0]); responseBase.setSerialNo(split[1]); responseBase.setRetCode(split[2]); if (length > 3){ responseBase.setErrorMsg(split[3]); } } } } return responseBase; } return null; } /** * 发送xml请求到server端 * @param url xml请求数据地址 * @param xmlString 发送的xml数据流 * @return null发送失败,否则返回响应内容 */ public String sendPost(String url,String xmlString){ //创建httpclient工具对象 HttpClient client = new HttpClient(); //创建post请求方法 PostMethod myPost = new PostMethod(url); //设置请求超时时间 // client.setConnectionTimeout(3000*1000); String responseString = null; try{ //设置请求头部类型 myPost.setRequestHeader("Content-Type","text/xml;charset=utf-8"); //设置请求体,即xml文本内容,一种是直接获取xml内容字符串,一种是读取xml文件以流的形式 myPost.setRequestBody(xmlString); int statusCode = client.executeMethod(myPost); //只有请求成功200了,才做处理 if(statusCode == HttpStatus.SC_OK){ InputStream inputStream = myPost.getResponseBodyAsStream(); // BufferedReader br = new BufferedReader(new InputStreamReader(inputStream,"UTF-8")); // StringBuffer stringBuffer = new StringBuffer(); // String str = ""; // while ((str = br.readLine()) != null) { // stringBuffer.append(str); // } // responseString = stringBuffer.toString(); responseString = convertStreamToString(inputStream); } }catch (Exception e) { e.printStackTrace(); }finally{ myPost.releaseConnection(); } return responseString; } public String convertStreamToString(InputStream is) { StringBuilder sb1 = new StringBuilder(); byte[] bytes = new byte[4096]; int size = 0; try { while ((size = is.read(bytes)) > 0) { String str = new String(bytes, 0, size, "UTF-8"); sb1.append(str); } } catch (IOException e) { e.printStackTrace(); } finally { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } return sb1.toString(); } /** * 1. sessionId为会话编号,每次登录之后会产生一个唯一的编号,用于标识这次会话。用户每次进行交易时都必须上送该Id。如果是登录交易,则请求报文头中的sessionId传-1即可。 * 2. serviceId为服务编号,用以区分不同的操作,见具体交易格式说明,如登录交易的服务编号为: CL0001。 * 3. serialNo为交易序列号,客户端唯一标识,返回时原样返回。 * 4. reqTime为请求时间,yyyyMMddHHmmss。 * 5. retCode和errorMsg为响应代码和错误信息,请求处理成功时,返回代码为’00000000’,错误信息留空;其它情况均视为请求处理失败。 * 6. 请求报文体和响应报文体为XML格式,封装了具体的交易数据,格式请参见下一章节描述。 * 7. 对于登录和转账等交易,请求报文体需要进行签名。 * 8. 登录后,企业客户如果在设定时间之内没有进行任何请求,该会话将被自动清理,需要重新登录后才可以进行一般交易请求。(目前暂定:设置超时时间为12小时) * 9. 如果sessionId对应的会话是超时或者非法的时候,服务端只会返回响应报文头“-1|EBLN0000|会话已超时,请重新登录|#”,不会返回报文体。 * 10. 如果请求的XML包格式不正确,或者opName指定的交易名称不正确时,服务器端也只会返回响应报文头,不会返回报文体。 * @param sessionId * @param serviceId * @return */ public String getRequestUrl(String ip,int port,String sessionId,String serviceId,String serialNo){ String url = "http://"+ip+":"+port; return url; } public String getTime(Date date){ return format.format(date); } public String sendSignRequestTCP(String oriData) { StringBuffer sb = new StringBuffer(""); Socket socket = null; BufferedInputStream in = null; BufferedOutputStream out = null; log.info("sign ip:"+ipSign); log.info("sign port:"+portSign); log.info("sign content:"+oriData); try { int length = oriData.getBytes(charset).length; byte[] buf = new byte[length + 5]; String lenValue = String.valueOf(length); System.arraycopy(oriData.getBytes(charset), 0, buf, 5, length); for (int i = 0; i < 5; i++) buf[i] = '0'; int idx = 0; for (int i = 5 - lenValue.length(); i < 5; i++) { buf[i] = (byte) lenValue.charAt(idx++); } socket = new Socket(ipSign, portSign); out = new BufferedOutputStream(socket.getOutputStream()); out.write(buf); out.flush(); in = new BufferedInputStream(socket.getInputStream()); byte[] buffer = new byte[1024]; int len = 0; while ((len = in.read(buffer)) != -1) { sb.append(new String(buffer, 0, len, charset)); } } catch (Exception e) { sb = new StringBuffer("-1"); e.printStackTrace(); } finally { try { if (null != socket) { socket.close(); } } catch (Exception e) { e.printStackTrace(); } try { if (out != null) out.close(); } catch (Exception e) { e.printStackTrace(); } try { if (in != null) in.close(); } catch (Exception e) { e.printStackTrace(); } } return sb.toString(); } /** * * * 0 * 1005 * 0 * 1 * * * 签名原文的长度 * 签名原文 * * * @param paramData * @return */ public String packSignXml(Object paramData) throws Exception { if (paramData == null){ return null; } JSONObject si = new JSONObject(); si.put("ReqParam",JSONObject.toJSON(paramData)); String sJson = JsonAndXmlUtils.JsonToXml((JSONObject) JSONObject.parse(JSONObject.toJSONString(si))); String substring = sJson.substring(sJson.lastIndexOf("")); log.info("签名后的数据:"+substring); JSONObject head =new JSONObject(); head.put("msg_type",0); head.put("msg_id",1005); head.put("msg_sn",0); head.put("version",1); JSONObject body = new JSONObject(); body.put("origin_data_len",substring.length()); body.put("origin_data","dataDataJxml"); JSONObject msg = new JSONObject(); msg.put("msg_head",head); msg.put("msg_body",body); JSONObject req = new JSONObject(); req.put("msg",msg); String s = JsonAndXmlUtils.JsonToXml(req); String dataDataJxml = s.replace("dataDataJxml", substring); String s1 = sendSignRequestTCP(dataDataJxml); String s2 = xmlToSignData(s1); log.info("sign return data :"+s1); log.info("data sign content :"+s2); return s2; } public String xmlToSignData(String xmlString) throws DocumentException { JSONObject jsonObject = JsonAndXmlUtils.xmlToJson(xmlString); if (jsonObject.containsKey("msg")){ JSONObject msg = (JSONObject)jsonObject.get("msg"); if (msg.containsKey("msg_body")){ JSONObject msg_body = (JSONObject)msg.get("msg_body"); if (msg_body.containsKey("signed_data")){ String signed_data = msg_body.get("signed_data").toString(); return replaceBlank(signed_data); } } } return null; } public String replaceBlank(String str) { String dest = ""; if (str!=null) { Pattern p = Pattern.compile("\\s*|\t|\r|\n"); Matcher m = p.matcher(str); dest = m.replaceAll(""); } return dest; } public void cacheLoginSession(BankLoginUserRespBO bankLoginUserRespBO){ ValueOperations ops = redisTemplate.opsForValue(); ops.set("cqcarbon.bank.user.sessionId",bankLoginUserRespBO,12*3600, TimeUnit.SECONDS); } public BankLoginUserRespBO getLoginSession(){ ValueOperations ops = redisTemplate.opsForValue(); BankLoginUserRespBO o = (BankLoginUserRespBO)ops.get("cqcarbon.bank.user.sessionId"); if (o != null){ return o; } return null; } }