├── C# └── zb_api_c#.cs ├── IOS(OC)_Sign加密示例 ├── IOS(OC)_Sign加密示例 │ ├── .DS_Store │ ├── CBExamples.h │ ├── CBExamples.m │ └── CBSignEncodeTools │ │ ├── CBSignEncodeTools.h │ │ └── CBSignEncodeTools.m └── __MACOSX │ └── IOS(OC)_Sign加密示例 │ ├── ._.DS_Store │ ├── ._CBExamples.h │ ├── ._CBExamples.m │ └── CBSignEncodeTools │ ├── ._CBSignEncodeTools.h │ └── ._CBSignEncodeTools.m ├── PHP └── zbapi.php ├── PYTHON ├── rest 接口 │ ├── python3 │ │ ├── test.py │ │ └── zapi.py │ ├── zb_api_python.py │ └── zb_api_python3.py └── websocket 接口 │ ├── readme │ ├── zb.com-api-master │ ├── README.md │ └── zb.comskd.py │ └── zb_py_socket │ ├── reame.txt │ ├── test.py │ ├── test.py.bak │ └── vnzb.py ├── README.md ├── golang └── zb-api-trade-master.zip ├── zb_api_rest_java ├── .classpath ├── .project ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── zb │ │ │ └── kits │ │ │ ├── EncryDigestUtil.java │ │ │ ├── HttpUtilManager.java │ │ │ ├── JsonFormatTool.java │ │ │ └── MapSort.java │ └── webapp │ │ └── WEB-INF │ │ └── web.xml │ └── test │ ├── java │ └── com │ │ └── zb │ │ └── api │ │ └── RestTest.java │ └── resources │ └── log4j.properties ├── zb_netty_client_java ├── pom.xml └── src │ └── main │ └── java │ ├── com │ ├── world │ │ ├── common │ │ │ ├── SysEnum.java │ │ │ ├── SystemCode.java │ │ │ └── VerifiUtil.java │ │ └── model │ │ │ ├── entitys │ │ │ ├── Balance.java │ │ │ ├── Base.java │ │ │ ├── Frozen.java │ │ │ └── Order.java │ │ │ └── market │ │ │ ├── Arith.java │ │ │ └── Market.java │ └── zb │ │ └── kits │ │ └── MapSort.java │ └── websocketx │ └── client │ ├── EncryDigestUtil.java │ ├── RunExample.java │ ├── WebSocketClient.java │ └── WebSocketClientHandler.java └── 易语言 ├── 中币api示例.e └── 精易模块5.7.ec /C#/zb_api_c#.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by SharpDevelop. 3 | * User: Administrator 4 | * Date: 2014/1/2 5 | * Time: 12:56 6 | * 7 | * To change this template use Tools | Options | Coding | Edit Standard Headers. 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using System.Linq; 12 | using System.Security.Cryptography; 13 | using System.Text; 14 | using System.Net; 15 | using System.IO; 16 | namespace zb { 17 | class zb_api { 18 | private static String encodingCharset = "UTF-8"; 19 | /** 20 | * 21 | * @param aValue 要加密的文字 22 | * @param aKey 密钥 23 | * @return 24 | */ 25 | public static String hmacSign(String aValue, String aKey) { 26 | byte[] k_ipad = new byte[64]; 27 | byte[] k_opad = new byte[64]; 28 | byte[] keyb; 29 | byte[] value; 30 | Encoding coding = Encoding.GetEncoding(encodingCharset); 31 | try { 32 | keyb = coding.GetBytes(aKey); 33 | // aKey.getBytes(encodingCharset); 34 | value = coding.GetBytes(aValue); 35 | // aValue.getBytes(encodingCharset); 36 | } 37 | catch (Exception e) { 38 | keyb = null; 39 | value =null; 40 | //throw; 41 | } 42 | for (int i = keyb.Length; i < 64; i++) { 43 | k_ipad[i] = (byte)54; 44 | k_opad[i] = (byte)92; 45 | } 46 | for (int i = 0; i < keyb.Length; i++) { 47 | k_ipad[i] = (byte) (keyb[i] ^ 0x36); 48 | k_opad[i] = (byte) (keyb[i] ^ 0x5c); 49 | } 50 | byte[] sMd5_1 = MakeMD5(k_ipad.Concat(value).ToArray()); 51 | byte[] dg = MakeMD5(k_opad.Concat(sMd5_1).ToArray()); 52 | return toHex(dg); 53 | } 54 | public static String toHex(byte[] input) { 55 | if (input == null) 56 | return null; 57 | StringBuilder output = new StringBuilder(input.Length * 2); 58 | for (int i = 0; i < input.Length; i++) { 59 | int current = input[i] & 0xff; 60 | if (current < 16) 61 | output.Append('0'); 62 | output.Append( current.ToString("x")); 63 | } 64 | return output.ToString(); 65 | } 66 | /** 67 | * 68 | * @param args 69 | * @param key 70 | * @return 71 | */ 72 | public static String getHmac(String[] args, String key) { 73 | if (args == null || args.Length == 0) { 74 | return (null); 75 | } 76 | StringBuilder str = new StringBuilder(); 77 | for (int i = 0; i < args.Length; i++) { 78 | str.Append(args[i]); 79 | } 80 | return (hmacSign(str.ToString(), key)); 81 | } 82 | /// 83 | /// 生成MD5摘要 84 | /// 85 | /// 数据源 86 | /// 摘要 87 | public static byte[] MakeMD5(byte[] original) { 88 | MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider(); 89 | byte[] keyhash = hashmd5.ComputeHash(original); 90 | hashmd5 = null; 91 | return keyhash; 92 | } 93 | /** 94 | * SHA加密 95 | * @param aValue 96 | * @return 97 | */ 98 | public static String digest(String aValue) { 99 | aValue = aValue.Trim(); 100 | byte[] value; 101 | SHA1 sha = null; 102 | Encoding coding = Encoding.GetEncoding(encodingCharset); 103 | try { 104 | value = coding.GetBytes(aValue); 105 | // aValue.getBytes(encodingCharset); 106 | HashAlgorithm ha=(HashAlgorithm) CryptoConfig.CreateFromName("SHA"); 107 | value= ha.ComputeHash(value); 108 | } 109 | catch (Exception e) { 110 | //value = coding.GetBytes(aValue); 111 | throw; 112 | } 113 | return toHex(value); 114 | } 115 | /** 116 | * API调用示例 117 | * 其他方法调用及返回说明请查看API交易文档 118 | */ 119 | public static String testGetAccountInfo() { 120 | String accesskey = "accesskey"; 121 | String secretkey = "secretkey"; 122 | String baseURL = "https://trade.zb.com/api/"; 123 | String param = "accesskey="+accesskey+"&method=getAccountInfo"; 124 | secretkey = digest(secretkey); 125 | String sign = hmacSign(param, secretkey); 126 | DateTime timeStamp=new DateTime(1970,1,1); 127 | //得到1970年的时间戳 128 | long stamp= (DateTime.UtcNow.Ticks - timeStamp.Ticks)/10000; 129 | //注意这里有时区问题,用now就要减掉8个小时 130 | baseURL += "getAccountInfo?" + param + "&sign=" + sign + "&reqTime=" + stamp; 131 | return HttpConnectToServer(baseURL); 132 | } 133 | /** 134 | * HttpConnectToServer 135 | */ 136 | public static string HttpConnectToServer(string url) { 137 | //创建请求 138 | HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url); 139 | request.Method = "POST"; 140 | request.ContentType = "application/x-www-form-urlencoded"; 141 | //读取返回消息 142 | string res = string.Empty; 143 | try { 144 | HttpWebResponse response = (HttpWebResponse)request.GetResponse(); 145 | StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8); 146 | res = reader.ReadToEnd(); 147 | reader.Close(); 148 | } 149 | catch (Exception ex) { 150 | return null; 151 | //连接服务器失败 152 | } 153 | return res; 154 | } 155 | public static void Main(string[] args) { 156 | // TODO: Implement Functionality Here 157 | //Console.WriteLine(hmacSign("administratorguoflyskyguosj","guosj")); 158 | //Console.WriteLine(digest("administratorguoflyskyguosj")); 159 | Console.WriteLine(testGetAccountInfo()); 160 | } 161 | } 162 | } -------------------------------------------------------------------------------- /IOS(OC)_Sign加密示例/IOS(OC)_Sign加密示例/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zb2017/api/4927d6940c9f217c91b11c042532827897f74927/IOS(OC)_Sign加密示例/IOS(OC)_Sign加密示例/.DS_Store -------------------------------------------------------------------------------- /IOS(OC)_Sign加密示例/IOS(OC)_Sign加密示例/CBExamples.h: -------------------------------------------------------------------------------- 1 | // 2 | // CBExamples.h 3 | // JXMovableCellTableView 4 | // 5 | // Created by 丁 on 2017/9/14. 6 | // Copyright © 2017年 jiaxin. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface CBExamples : NSObject 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /IOS(OC)_Sign加密示例/IOS(OC)_Sign加密示例/CBExamples.m: -------------------------------------------------------------------------------- 1 | // 2 | // CBExamples.m 3 | // JXMovableCellTableView 4 | // 5 | // Created by 丁 on 2017/9/14. 6 | // Copyright © 2017年 jiaxin. All rights reserved. 7 | // 8 | 9 | #import "CBExamples.h" 10 | #import "CBSignEncodeTools.h" 11 | 12 | @implementation CBExamples 13 | 14 | //加密sign 15 | -(void)encode{ 16 | 17 | /* 18 | 1) 先对 secretKey 进行 SHA 加密 19 | 2) 严格按照CHBTC文档 将参数按照顺序拼成字符串 20 | 3) 以 SHA加密后得到的字符串 为 key 对参数拼接字符串进行 HmacMD5 加密 21 | 3) 得到sign参数 22 | */ 23 | NSString *signStr = [CBSignEncodeTools HMACMD5WithString:@"参数拼接字符串" WithKey:[CBSignEncodeTools getShaString:@"Secret Key"]]; 24 | 25 | } 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /IOS(OC)_Sign加密示例/IOS(OC)_Sign加密示例/CBSignEncodeTools/CBSignEncodeTools.h: -------------------------------------------------------------------------------- 1 | // 2 | // SHA256.h 3 | // chbtc 4 | // 5 | // Created by 丁 on 2017/9/13. 6 | // Copyright © 2017年 丁. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface CBSignEncodeTools : NSObject 13 | 14 | /** sha加密方式 */ 15 | + (NSString *)getShaString:(NSString *)srcString; 16 | /** HmacMD5 加密 */ 17 | + (NSString *)HMACMD5WithString:(NSString *)toEncryptStr WithKey:(NSString *)keyStr; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /IOS(OC)_Sign加密示例/IOS(OC)_Sign加密示例/CBSignEncodeTools/CBSignEncodeTools.m: -------------------------------------------------------------------------------- 1 | // 2 | // SHA256.m 3 | // chbtc 4 | // 5 | // Created by 丁 on 2017/9/13. 6 | // Copyright © 2017年 丁. All rights reserved. 7 | // 8 | 9 | #import "CBSignEncodeTools.h" 10 | 11 | @implementation CBSignEncodeTools 12 | 13 | //sha加密方式 14 | + (NSString *)getShaString:(NSString *)srcString{ 15 | const char *cstr = [srcString cStringUsingEncoding:NSUTF8StringEncoding]; 16 | NSData *data = [NSData dataWithBytes:cstr length:srcString.length]; 17 | 18 | uint8_t digest[CC_SHA1_DIGEST_LENGTH]; 19 | 20 | CC_SHA1(data.bytes, (int)data.length, digest); 21 | 22 | NSMutableString* result = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2]; 23 | 24 | for(int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++) { 25 | [result appendFormat:@"%02x", digest[i]]; 26 | } 27 | 28 | return result; 29 | } 30 | 31 | 32 | 33 | //HmacMD5 加密 34 | + (NSString *)HMACMD5WithString:(NSString *)toEncryptStr WithKey:(NSString *)keyStr 35 | { 36 | const char *cKey = [keyStr cStringUsingEncoding:NSUTF8StringEncoding]; 37 | const char *cData = [toEncryptStr cStringUsingEncoding:NSUTF8StringEncoding]; 38 | const unsigned int blockSize = 64; 39 | char ipad[blockSize]; 40 | char opad[blockSize]; 41 | char keypad[blockSize]; 42 | 43 | unsigned int keyLen = (int)strlen(cKey); 44 | CC_MD5_CTX ctxt; 45 | if (keyLen > blockSize) { 46 | CC_MD5_Init(&ctxt); 47 | CC_MD5_Update(&ctxt, cKey, keyLen); 48 | CC_MD5_Final((unsigned char *)keypad, &ctxt); 49 | keyLen = CC_MD5_DIGEST_LENGTH; 50 | } 51 | else { 52 | memcpy(keypad, cKey, keyLen); 53 | } 54 | 55 | memset(ipad, 0x36, blockSize); 56 | memset(opad, 0x5c, blockSize); 57 | 58 | int i; 59 | for (i = 0; i < keyLen; i++) { 60 | ipad[i] ^= keypad[i]; 61 | opad[i] ^= keypad[i]; 62 | } 63 | 64 | CC_MD5_Init(&ctxt); 65 | CC_MD5_Update(&ctxt, ipad, blockSize); 66 | CC_MD5_Update(&ctxt, cData, (int)strlen(cData)); 67 | unsigned char md5[CC_MD5_DIGEST_LENGTH]; 68 | CC_MD5_Final(md5, &ctxt); 69 | 70 | CC_MD5_Init(&ctxt); 71 | CC_MD5_Update(&ctxt, opad, blockSize); 72 | CC_MD5_Update(&ctxt, md5, CC_MD5_DIGEST_LENGTH); 73 | CC_MD5_Final(md5, &ctxt); 74 | 75 | const unsigned int hex_len = CC_MD5_DIGEST_LENGTH*2+2; 76 | char hex[hex_len]; 77 | for(i = 0; i < CC_MD5_DIGEST_LENGTH; i++) { 78 | snprintf(&hex[i*2], hex_len-i*2, "%02x", md5[i]); 79 | } 80 | 81 | NSData *HMAC = [[NSData alloc] initWithBytes:hex length:strlen(hex)]; 82 | NSString *hash = [[NSString alloc] initWithData:HMAC encoding:NSUTF8StringEncoding]; 83 | 84 | return hash; 85 | } 86 | 87 | 88 | 89 | @end 90 | -------------------------------------------------------------------------------- /IOS(OC)_Sign加密示例/__MACOSX/IOS(OC)_Sign加密示例/._.DS_Store: -------------------------------------------------------------------------------- 1 | Mac OS X  2Fx ATTRxx -------------------------------------------------------------------------------- /IOS(OC)_Sign加密示例/__MACOSX/IOS(OC)_Sign加密示例/._CBExamples.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zb2017/api/4927d6940c9f217c91b11c042532827897f74927/IOS(OC)_Sign加密示例/__MACOSX/IOS(OC)_Sign加密示例/._CBExamples.h -------------------------------------------------------------------------------- /IOS(OC)_Sign加密示例/__MACOSX/IOS(OC)_Sign加密示例/._CBExamples.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zb2017/api/4927d6940c9f217c91b11c042532827897f74927/IOS(OC)_Sign加密示例/__MACOSX/IOS(OC)_Sign加密示例/._CBExamples.m -------------------------------------------------------------------------------- /IOS(OC)_Sign加密示例/__MACOSX/IOS(OC)_Sign加密示例/CBSignEncodeTools/._CBSignEncodeTools.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zb2017/api/4927d6940c9f217c91b11c042532827897f74927/IOS(OC)_Sign加密示例/__MACOSX/IOS(OC)_Sign加密示例/CBSignEncodeTools/._CBSignEncodeTools.h -------------------------------------------------------------------------------- /IOS(OC)_Sign加密示例/__MACOSX/IOS(OC)_Sign加密示例/CBSignEncodeTools/._CBSignEncodeTools.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zb2017/api/4927d6940c9f217c91b11c042532827897f74927/IOS(OC)_Sign加密示例/__MACOSX/IOS(OC)_Sign加密示例/CBSignEncodeTools/._CBSignEncodeTools.m -------------------------------------------------------------------------------- /PHP/zbapi.php: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | zb 6 | 7 | Fund(); 11 | //var_dump($Fond_zb); 12 | 13 | class zbAPI { 14 | var $access_key="***"; 15 | var $secret_key="***"; 16 | 17 | function httpRequest($pUrl, $pData){ 18 | $tCh = curl_init(); 19 | curl_setopt($tCh, CURLOPT_POST, true); 20 | curl_setopt($tCh, CURLOPT_POSTFIELDS, $pData); 21 | curl_setopt($tCh, CURLOPT_HTTPHEADER, array("Content-type: application/x-www-form-urlencoded")); 22 | curl_setopt($tCh, CURLOPT_URL, $pUrl); 23 | curl_setopt($tCh, CURLOPT_RETURNTRANSFER, true); 24 | curl_setopt($tCh, CURLOPT_SSL_VERIFYPEER, false); 25 | $tResult = curl_exec($tCh); 26 | curl_close($tCh); 27 | $tResult=json_decode ($tResult,true); 28 | return $tResult; 29 | } 30 | 31 | function HangqingRequest($pUrl){ 32 | $tCh = curl_init(); 33 | curl_setopt($tCh, CURLOPT_URL, $pUrl); 34 | curl_setopt($tCh, CURLOPT_RETURNTRANSFER, true); 35 | curl_setopt($tCh, CURLOPT_SSL_VERIFYPEER, false); 36 | curl_setopt($tCh, CURLOPT_TIMEOUT, 1); 37 | $tResult = curl_exec($tCh); 38 | curl_close($tCh); 39 | $tResult=json_decode ($tResult,true); 40 | return $tResult; 41 | } 42 | 43 | function createSign($pParams = array()){ 44 | $tPreSign = http_build_query($pParams, '', '&'); 45 | $SecretKey = sha1($this->secret_key); 46 | $tSign=hash_hmac('md5',$tPreSign,$SecretKey); 47 | $pParams['sign'] = $tSign; 48 | $pParams['reqTime'] = time()*1000; 49 | $tResult=http_build_query($pParams, '', '&'); 50 | return $tResult; 51 | } 52 | 53 | function Hangqing(){ 54 | $Url_btc="http://api.zb.com/data/v1/ticker?currency=btc"; 55 | $res=array(); 56 | $res=$this->HangqingRequest($Url_btc); 57 | return $res; 58 | } 59 | 60 | function MarketDepth($N=20){ 61 | $res=$this->HangqingBtc(); 62 | $res_ask=array_reverse(array_slice($res["asks"] , -$N, $N)); 63 | $res_bid=array_slice($res["bids"] , 0, $N) ; 64 | $ans=array("asks"=>$res_ask,"bids"=>$res_bid); 65 | return $ans; 66 | } 67 | 68 | 69 | //BTC 下单 70 | function Trade($Price,$Amount,$Tradetype){ 71 | $parameters=array("accesskey"=>$this->access_key,"amount"=>$Amount,"currency"=>"btc","method"=>"order","price"=>$Price,"tradeType"=>$Tradetype); 72 | $url= "https://trade.zb.com/api/order"; 73 | $post=$this->createSign($parameters); 74 | $res=$this->httpRequest($url,$post); 75 | return $res; 76 | } 77 | 78 | //BTC 取消订单 79 | function CancelOrder($OrderID){ 80 | $parameters=array("accesskey"=>$this->access_key,"currency"=>"btc","id"=>$OrderID,"method"=>"cancelOrder"); 81 | $url='https://trade.zb.com/api/cancelOrder'; 82 | $post=$this->createSign($parameters); 83 | $res=$this->httpRequest($url,$post); 84 | return $res; 85 | } 86 | 87 | //LTC 取消订单 88 | function CancelOrder_ltc($OrderID){ 89 | $parameters=array("accesskey"=>$this->access_key,"currency"=>"ltc","id"=>$OrderID,"method"=>"cancelOrder"); 90 | $url='https://trade.zb.com/api/cancelOrder'; 91 | $post=$this->createSign($parameters); 92 | $res=$this->httpRequest($url,$post); 93 | return $res; 94 | } 95 | 96 | 97 | function Fund(){ 98 | $parameters=array("accesskey"=>$this->access_key,"method"=>"getAccountInfo"); 99 | $url='https://trade.zb.com/api/getAccountInfo'; 100 | $post=$this->createSign($parameters); 101 | $res=$this->httpRequest($url,$post); 102 | return $res; 103 | } 104 | 105 | //获取订单信息 106 | function GetOrder($OrderID){ 107 | $parameters=array("accesskey"=>$this->access_key,"currency"=>"btc","id"=>$OrderID,"method"=>"getOrder"); 108 | $url= 'https://trade.zb.com/api/getOrder'; 109 | $post=$this->createSign($parameters); 110 | $res=$this->httpRequest($url,$post); 111 | return $res; 112 | } 113 | 114 | //获取订单信息 115 | function GetOrder_ltc($OrderID){ 116 | $parameters=array("accesskey"=>$this->access_key,"currency"=>"ltc","id"=>$OrderID,"method"=>"getOrder"); 117 | $url= 'https://trade.zb.com/api/getOrder'; 118 | $post=$this->createSign($parameters); 119 | $res=$this->httpRequest($url,$post); 120 | return $res; 121 | } 122 | 123 | } 124 | ?> 125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /PYTHON/rest 接口/python3/test.py: -------------------------------------------------------------------------------- 1 | 2 | from zapi import ZApi 3 | 4 | 5 | 6 | 7 | 8 | if __name__ == '__main__': 9 | zb = ZApi(access_key='ffff', secret_key='ddddd') 10 | # a = zb.all_ticker() 11 | a = zb.order( "bts_usdt", 1, 0.1, 0.1) 12 | print(a) 13 | 14 | 15 | -------------------------------------------------------------------------------- /PYTHON/rest 接口/python3/zapi.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | import struct 3 | # import sha 4 | import time 5 | import requests 6 | 7 | 8 | suc_codes = ["1000"] 9 | 10 | DEBUG = True 11 | 12 | errcode = { 13 | "1000": "success", 14 | "1001": "normal error", 15 | "1002": "internal error", 16 | "1003": "verify not passed", 17 | "1004": "fund security password locked", 18 | "1005": "fund security password not right", 19 | "1006": "real-name authentication verifying or not passed", 20 | "1009": "current api not in service", 21 | "2001": "RMB not sufficient", 22 | "2002": "BTC not sufficient", 23 | "2003": "LTC not sufficient", 24 | "2005": "ETH not sufficient", 25 | "2006": "ETC not sufficient", 26 | "2007": "BTS not sufficient", 27 | "2009": "balance not sufficient", 28 | "3001": "order not found", 29 | "3002": "invalid amount of money", 30 | "3003": "invalid count", 31 | "3004": "user not exists", 32 | "3005": "illegal argument", 33 | "3006": "IP error", 34 | "3007": "time expired", 35 | "3008": "trade history not found", 36 | "4001": "API locked or not opened", 37 | "4002": "requests too frequently" 38 | } 39 | 40 | ORDER_TYPE_BUY = 1 41 | ORDER_TYPE_SELL = 0 42 | 43 | ORDER_STATUS_CANCELED = 1 44 | ORDER_STATUS_DONE = 2 45 | ORDER_STATUS_WAITING = 3 46 | 47 | TPL_MARKETS = 'http://api.zb.com/data/v1/markets' 48 | TPL_ALL_MARKET = 'http://api.zb.cn/data/v1/allTicker' 49 | TPL_MARKET = 'http://api.zb.com/data/v1/ticker?market={MARKET}' 50 | TPL_DEPTH = 'http://api.zb.com/data/v1/depth?market={MARKET}&size={SIZE}' 51 | TPL_TRADES = 'http://api.zb.com/data/v1/trades?market={MARKET}' 52 | TPL_KLINE = 'http://api.zb.com/data/v1/kline?market={MARKET}' 53 | 54 | URL_ORDER = 'https://trade.zb.com/api/order' 55 | URL_CANCEL_ORDER = 'https://trade.zb.com/api/cancelOrder' 56 | URL_GET_ORDER = 'https://trade.zb.com/api/getOrder' 57 | URL_GET_ORDERS = 'https://trade.zb.com/api/getOrders' 58 | URL_GET_ORDERS_NEW = 'https://trade.zb.com/api/getOrdersNew' 59 | URL_GET_ORDERS_IGNORE_TRADE_TYPE = 'https://trade.zb.com/api/getOrdersIgnoreTradeType' 60 | URL_GET_UNFINISHED_ORDERS_IGNORE_TRADE_TYPE = 'https://trade.zb.com/api/getUnfinishedOrdersIgnoreTradeType' 61 | URL_GET_ACCOUNT_INFO = 'https://trade.zb.com/api/getAccountInfo' 62 | URL_GET_USER_ADDRESS = 'https://trade.zb.com/api/getUserAddress' 63 | URL_GET_WITHDRAW_ADDRESS = 'https://trade.zb.com/api/getWithdrawAddress' 64 | URL_GET_WITHDRAW_RECORD = 'https://trade.zb.com/api/getWithdrawRecord' 65 | URL_GET_CHARGE_RECORD = 'https://trade.zb.com/api/getChargeRecord' 66 | URL_WITHDRAW = 'https://trade.zb.com/api/withdraw' 67 | 68 | URL_doTransferFunds = 'https://trade.zb.cn/api/doTransferFunds' 69 | 70 | class ZApi: 71 | def __init__(self, access_key, secret_key): 72 | """ 73 | opened markets and status, format: 74 | { 75 | "btc_usdt": { 76 | "amountScale": 4, 77 | "priceScale": 2 78 | }, 79 | "ltc_usdt": { 80 | "amountScale": 3, 81 | "priceScale": 2 82 | } 83 | ... 84 | } 85 | """ 86 | self._access_key_ = access_key 87 | self._secret_key_ = secret_key 88 | self._markets_ = self.markets() 89 | if len(self._markets_) < 1: 90 | raise Exception("Get markets status failed") 91 | 92 | def get(self, url): 93 | while True: 94 | try: 95 | r = requests.get(url) 96 | except Exception: 97 | time.sleep(0.5) 98 | continue 99 | if r.status_code != 200: 100 | time.sleep(0.5) 101 | continue 102 | r_info = r.json() 103 | r.close() 104 | return r_info 105 | 106 | def check_market_code(self, market): 107 | if not market: 108 | return False 109 | if market not in self._markets_: 110 | return False 111 | else: 112 | return True 113 | 114 | def markets(self): 115 | """ 116 | markets data, result format: 117 | { 118 | "btc_usdt": { 119 | "amountScale": 4, 120 | "priceScale": 2 121 | }, 122 | "ltc_usdt": { 123 | "amountScale": 3, 124 | "priceScale": 2 125 | } 126 | ... 127 | } 128 | :return: result data of markets 129 | """ 130 | url = TPL_MARKETS 131 | return self.get(url) 132 | def all_ticker(self,): 133 | """ 134 | ticker data, result format: 135 | { 136 | "ticker": { 137 | "vol": "40.463", 138 | "last": "0.899999", 139 | "sell": "0.5", 140 | "buy": "0.225", 141 | "high": "0.899999", 142 | "low": "0.081" 143 | }, 144 | "date": "1507875747359" 145 | } 146 | :param market: market code string 147 | :return: ticker result 148 | """ 149 | url = TPL_ALL_MARKET 150 | return self.get(url) 151 | 152 | def ticker(self, market): 153 | """ 154 | ticker data, result format: 155 | { 156 | "ticker": { 157 | "vol": "40.463", 158 | "last": "0.899999", 159 | "sell": "0.5", 160 | "buy": "0.225", 161 | "high": "0.899999", 162 | "low": "0.081" 163 | }, 164 | "date": "1507875747359" 165 | } 166 | :param market: market code string 167 | :return: ticker result 168 | """ 169 | url = TPL_MARKET.format(MARKET=market) 170 | return self.get(url) 171 | 172 | def depth(self, market, size): 173 | """ 174 | depth data of specific market, result format: 175 | { 176 | "asks": [ 177 | [ 178 | 83.28, 179 | 11.8 180 | ]... 181 | ], 182 | "bids": [ 183 | [ 184 | 81.91, 185 | 3.65 186 | ]... 187 | ], 188 | "timestamp" : timestamp 189 | } 190 | :param market: market code string 191 | :param size: depth size 192 | :return: result depth data 193 | """ 194 | url = TPL_DEPTH.format(MARKET=market, SIZE=str(size)) 195 | return self.get(url) 196 | 197 | def trades(self, market): 198 | """ 199 | trade history, result format: 200 | [ 201 | { 202 | "amount": 0.541, 203 | "date": 1472711925, 204 | "price": 81.87, 205 | "tid": 16497097, 206 | "trade_type": "ask", 207 | "type": "sell" 208 | }... 209 | ] 210 | :return: trade history data 211 | """ 212 | url = TPL_TRADES.format(MARKET=market) 213 | return self.get(url) 214 | 215 | def kline(self, market): 216 | """ 217 | kline data, result format: 218 | { 219 | "data": [ 220 | [ 221 | 1472107500000, 222 | 3840.46, 223 | 3843.56, 224 | 3839.58, 225 | 3843.3, 226 | 492.456 227 | ]... 228 | ], 229 | "moneyType": "btc", 230 | "symbol": "ltc" 231 | } 232 | :param market: market code 233 | :return: kline data 234 | """ 235 | url = TPL_KLINE.format(MARKET=market) 236 | return self.get(url) 237 | 238 | def order(self, market, type, amount, price): 239 | """ 240 | order api, result format: 241 | { 242 | "code": "1000", 243 | "message": "***", 244 | "id": "20131228361867" 245 | } 246 | :param market: currency 247 | :param type: ORDER_TYPE_BUY or ORDER_TYPE_SELL 248 | :param amount: order amount 249 | :param price: order price 250 | :return: order result 251 | """ 252 | params = 'accesskey=%s&amount=%s¤cy=%s&method=order&price=%s&tradeType=%s' % (self._access_key_, amount, market, price, type) 253 | return self.call_api(url=URL_ORDER, params=params) 254 | 255 | def cancel_order(self, market, order_id): 256 | """ 257 | cancel an order, result format: 258 | { 259 | "code": "1000", 260 | "message": "***" 261 | } 262 | :param market: currency 263 | :param order_id: order id 264 | :return: result 265 | """ 266 | params = 'accesskey=%s¤cy=%s&id=%s&method=cancelOrder' % (self._access_key_, market, order_id) 267 | return self.call_api(url=URL_CANCEL_ORDER, params=params) 268 | 269 | def cancel_allorder(self,market,page_index=1, page_size=5): 270 | flag = False 271 | orders = self.get_unfinished_orders_ignore_trade_type(market,page_index, page_size) 272 | #print('order',orders) 273 | if isinstance(orders,list) and len(orders) > 0 and 'id' in orders[0].keys(): 274 | flag = True 275 | while flag : 276 | time.sleep(0.1) 277 | for order in orders: 278 | #print(market,orders) 279 | self.cancel_order(market,order['id']) 280 | orders = self.get_unfinished_orders_ignore_trade_type(market,page_index, page_size) 281 | if isinstance(orders,list) and len(orders) > 0 and 'id' in orders[0].keys(): 282 | flag = True 283 | else : 284 | print('%s撤销所有订单完成!返回%s:'%(market,orders)) 285 | flag = False 286 | 287 | def get_order(self, market, order_id): 288 | """ 289 | get order detail, result format: 290 | { 291 | "currency": "btc", 292 | "id": "20150928158614292", 293 | "price": 1560, 294 | "status": 3, 295 | "total_amount": 0.1, 296 | "trade_amount": 0, 297 | "trade_price" : 6000, 298 | "trade_date": 1443410396717, 299 | "trade_money": 0, 300 | "type": 0, 301 | } 302 | :param market: currency 303 | :param order_id: order id 304 | :return: result 305 | """ 306 | params = 'accesskey=%s¤cy=%s&id=%s&method=getOrder' % (self._access_key_, market, order_id) 307 | return self.call_api(url=URL_GET_ORDER, params=params) 308 | 309 | def get_orders(self, market, page, type): 310 | """ 311 | get multiple orders, result format: 312 | [ 313 | { 314 | "currency": "btc", 315 | "id": "20150928158614292", 316 | "price": 1560, 317 | "status": 3, 318 | "total_amount": 0.1, 319 | "trade_amount": 0, 320 | "trade_price" : 6000, 321 | "trade_date": 1443410396717, 322 | "trade_money": 0, 323 | "type": 0 324 | }... 325 | ] 326 | :param market: currency 327 | :param page: page index 328 | :param type: order type 329 | :return: result 330 | """ 331 | params = 'accesskey=%s¤cy=%s&method=getOrders&pageIndex=%s&tradeType=%s' % (self._access_key_, market, page, type) 332 | return self.call_api(url=URL_GET_ORDERS, params=params) 333 | 334 | def get_orders_new(self, market, page_index, page_size, type): 335 | """ 336 | get multiple orders, result format same as get_orders 337 | :param market: currency 338 | :param page_index: page index 339 | :param page_size: page size 340 | :param type: order type 341 | :return: result 342 | """ 343 | params = 'accesskey=%s¤cy=%s&method=getOrdersNew&pageIndex=%s&pageSize=%s&tradeType=%s' % (self._access_key_, market, page_index, page_size, type) 344 | return self.call_api(url=URL_GET_ORDERS_NEW, params=params) 345 | 346 | def get_orders_ignore_tader_type(self, market, page_index, page_size): 347 | """ 348 | get multiple orders ignore type, result format same as get_orders 349 | :param market: currency 350 | :param page_index: page index 351 | :param page_size: page size 352 | :return: result 353 | """ 354 | params = 'accesskey=%s¤cy=%s&method=getOrdersIgnoreTradeType&pageIndex=%s&pageSize=%s' % (self._access_key_, market, page_index, page_size) 355 | return self.call_api(url=URL_GET_ORDERS_IGNORE_TRADE_TYPE, params=params) 356 | 357 | def get_unfinished_orders_ignore_trade_type(self, market, page_index, page_size): 358 | """ 359 | get multiple unfinished orders ignore type, result format same as get_orders 360 | :param market: currency 361 | :param page_index: page index 362 | :param page_size: page size 363 | :return: result 364 | """ 365 | params = 'accesskey=%s¤cy=%s&method=getUnfinishedOrdersIgnoreTradeType&pageIndex=%s&pageSize=%s' % (self._access_key_, market, page_index, page_size) 366 | # print(params) 367 | return self.call_api(url=URL_GET_UNFINISHED_ORDERS_IGNORE_TRADE_TYPE, params=params) 368 | 369 | def zhuanzhang_zi(self,amount,currency,fromUerName,toUserName): 370 | """ 371 | get multiple unfinished orders ignore type, result format same as get_orders 372 | :param market: currency 373 | :param page_index: page index 374 | :param page_size: page size 375 | :return: result 376 | """ 377 | params = 'accesskey=%s&amount=%s¤cy=%s&fromUserName=%s&method=doTransferFunds&toUserName=%s' % (self._access_key_, amount,currency,fromUerName,toUserName) 378 | return self.call_api(url='https://trade.zb.cn/api/doTransferFunds', params=params) 379 | def huoquzizhanghao(self): 380 | """: 381 | """ 382 | # params = 'accesskey=%s&method=getAccountInfo' % self._access_key_ 383 | params = 'accesskey=%s&method=getSubUserList' % self._access_key_ 384 | 385 | return self.call_api(url='https://trade.zb.cn/api/getSubUserList', params=params) 386 | 387 | def chuangjianzi(self): 388 | """: 389 | """ 390 | # params = 'accesskey=%s&method=getAccountInfo' % self._access_key_ 391 | params = 'accesskey=%s&method=getSubUserList' % self._access_key_ 392 | params = 'accesskey=%s&memo=%s&password=%s&method=addSubUser&subUserName=ceshi11' % (self._access_key_, 'ceshi11', '1234qwer') 393 | return self.call_api(url='https://trade.zb.cn/api/addSubUser', params=params) 394 | 395 | 396 | def get_account_info(self): 397 | """ 398 | get account information, result format: 399 | { 400 | "result": { 401 | "coins": [ 402 | { 403 | "freez": "0.00000000", 404 | "enName": "BTC", 405 | "unitDecimal": 8, 406 | "cnName": "BTC", 407 | "unitTag": "*", 408 | "available": "0.00000000", 409 | "key": "btc" 410 | }, 411 | { 412 | "freez": "0.00000000", 413 | "enName": "LTC", 414 | "unitDecimal": 8, 415 | "cnName": "LTC", 416 | "unitTag": "*", 417 | "available": "0.00000000", 418 | "key": "ltc" 419 | }, 420 | ... 421 | ], 422 | "base": { 423 | "username": "134150***", 424 | "trade_password_enabled": true, 425 | "auth_google_enabled": false, 426 | "auth_mobile_enabled": true 427 | } 428 | } 429 | } 430 | :return: result 431 | """ 432 | params = 'accesskey=%s&method=getAccountInfo' % self._access_key_ 433 | return self.call_api(url=URL_GET_ACCOUNT_INFO, params=params) 434 | 435 | def get_user_address(self, currency): 436 | """ 437 | get user address, result format: 438 | { 439 | "code": 1000, 440 | "message": { 441 | "des": "success", 442 | "isSuc": true, 443 | "datas": { 444 | "key": "0x0af7f36b8f09410f3df62c81e5846da673d4d9a9" 445 | } 446 | } 447 | } 448 | :param currency: currency 449 | :return: result 450 | """ 451 | params = 'accesskey=%s¤cy=%s&method=getUserAddress' % (self._access_key_, currency) 452 | return self.call_api(url=URL_GET_USER_ADDRESS, params=params) 453 | 454 | def get_withdraw_address(self, currency): 455 | """ 456 | get withdraw address, result format: 457 | { 458 | "code": 1000, 459 | "message": { 460 | "des": "success", 461 | "isSuc": true, 462 | "datas": { 463 | "key": "0x0af7f36b8f09410f3df62c81e5846da673d4d9a9" 464 | } 465 | } 466 | } 467 | :param currency: currency 468 | :return: result 469 | """ 470 | params = 'accesskey=%s¤cy=%s&method=getWithdrawAddress' % (self._access_key_, currency) 471 | return self.call_api(url=URL_GET_WITHDRAW_ADDRESS, params=params) 472 | 473 | def get_withdraw_record(self, currency, page_index, page_size): 474 | """ 475 | get withdraw record, result format: 476 | { 477 | "code": 1000, 478 | "message": { 479 | "des": "success", 480 | "isSuc": true, 481 | "datas": { 482 | "list": [ 483 | { 484 | "amount": 0.01, 485 | "fees": 0.001, 486 | "id": 2016042556231, 487 | "manageTime": 1461579340000, 488 | "status": 3, 489 | "submitTime": 1461579288000, 490 | "toAddress": "14fxEPirL9fyfw1i9EF439Pq6gQ5xijUmp" 491 | }... 492 | ], 493 | "pageIndex": 1, 494 | "pageSize": 10, 495 | "totalCount": 4, 496 | "totalPage": 1 497 | } 498 | } 499 | } 500 | :param currency: 501 | :param page_index: 502 | :param page_size: 503 | :return: 504 | """ 505 | params = 'accesskey=%s¤cy=%s&method=getWithdrawRecord&pageIndex=%s&pageSize=%s' % (self._access_key_, currency, page_index, page_size) 506 | return self.call_api(url=URL_GET_WITHDRAW_RECORD, params=params) 507 | 508 | def get_charge_record(self, currency, page_index, page_size): 509 | """ 510 | get charge record, result format: 511 | { 512 | "code": 1000, 513 | "message": { 514 | "des": "success", 515 | "isSuc": true, 516 | "datas": { 517 | "list": [ 518 | { 519 | "address": "1FKN1DZqCm8HaTujDioRL2Aezdh7Qj7xxx", 520 | "amount": "1.00000000", 521 | "confirmTimes": 1, 522 | "currency": "BTC", 523 | "description": "***", 524 | "hash": "7ce842de187c379abafadd64a5fe66c5c61c8a21fb04edff9532234a1dae6xxx", 525 | "id": 558, 526 | "itransfer": 1, 527 | "status": 2, 528 | "submit_time": "2016-12-07 18:51:57" 529 | }... 530 | ], 531 | "pageIndex": 1, 532 | "pageSize": 10, 533 | "total": 8 534 | } 535 | } 536 | } 537 | :param currency: currency 538 | :param page_index: page index 539 | :param page_size: page size 540 | :return: result 541 | """ 542 | params = 'accesskey=%s¤cy=%s&method=getChargeRecord&pageIndex=%s&pageSize=%s' % (self._access_key_, currency, page_index, page_size) 543 | return self.call_api(url=URL_GET_CHARGE_RECORD, params=params) 544 | 545 | def withdraw(self, currency, amount, fees, itransfer, addr, pwd): 546 | """ 547 | withdraw coins, result format: 548 | { 549 | "code": 1000, 550 | "message": "success", 551 | "id": "***" 552 | } 553 | :param currency: currency 554 | :param amount: amount 555 | :param fees: fees 556 | :param itransfer: itransfer 557 | :param addr: receive address 558 | :param pwd: safe password of current account 559 | :return: result 560 | """ 561 | params = 'accesskey=%s&amount=%s¤cy=%s&fees=%s&itransfer=%s&method=withdraw&receiveAddr=%s&safePwd=%s' % (self._access_key, amount, currency, fees, itransfer, addr, pwd) 562 | return self.call_api(url=URL_WITHDRAW, params=params) 563 | 564 | def call_api(self, url, params=''): 565 | full_url = url 566 | if params: 567 | sha_secret = self.digest(self._secret_key_) 568 | sign = self.hmac_sign(params, sha_secret) 569 | req_time = int(round(time.time() * 1000)) 570 | params += '&sign=%s&reqTime=%d' % (sign, req_time) 571 | full_url += '?' + params 572 | result = {} 573 | while True: 574 | try: 575 | r = requests.get(full_url, timeout=2) 576 | except Exception: 577 | time.sleep(0.5) 578 | continue 579 | if r.status_code != 200: 580 | time.sleep(0.5) 581 | r.close() 582 | continue 583 | else: 584 | result = r.json() 585 | r.close() 586 | break 587 | return result 588 | 589 | @staticmethod 590 | def fill(value, lenght, fill_byte): 591 | if len(value) >= lenght: 592 | return value 593 | else: 594 | fill_size = lenght - len(value) 595 | return value + chr(fill_byte) * fill_size 596 | 597 | @staticmethod 598 | def xor(s, value): 599 | slist = list(s.decode('utf-8')) 600 | for index in range(len(slist)): 601 | slist[index] = chr(ord(slist[index]) ^ value) 602 | return "".join(slist) 603 | 604 | def hmac_sign(self, arg_value, arg_key): 605 | keyb = struct.pack("%ds" % len(arg_key), arg_key.encode('utf-8')) 606 | value = struct.pack("%ds" % len(arg_value), arg_value.encode('utf-8')) 607 | k_ipad = self.xor(keyb, 0x36) 608 | k_opad = self.xor(keyb, 0x5c) 609 | k_ipad = self.fill(k_ipad, 64, 54) 610 | k_opad = self.fill(k_opad, 64, 92) 611 | m = hashlib.md5() 612 | m.update(k_ipad.encode('utf-8')) 613 | m.update(value) 614 | dg = m.digest() 615 | 616 | m = hashlib.md5() 617 | m.update(k_opad.encode('utf-8')) 618 | subStr = dg[0:16] 619 | m.update(subStr) 620 | dg = m.hexdigest() 621 | return dg 622 | 623 | def digest(self, arg_value): 624 | value = struct.pack("%ds" % len(arg_value), arg_value.encode('utf-8')) 625 | h = hashlib.sha1() 626 | h.update(value) 627 | dg = h.hexdigest() 628 | return dg 629 | 630 | 631 | 632 | -------------------------------------------------------------------------------- /PYTHON/rest 接口/zb_api_python.py: -------------------------------------------------------------------------------- 1 | import json, urllib2, hashlib,struct,sha,time 2 | 3 | class zb_api: 4 | 5 | def __init__(self, mykey, mysecret): 6 | self.mykey = mykey 7 | self.mysecret = mysecret 8 | 9 | def __fill(self, value, lenght, fillByte): 10 | if len(value) >= lenght: 11 | return value 12 | else: 13 | fillSize = lenght - len(value) 14 | return value + chr(fillByte) * fillSize 15 | 16 | def __doXOr(self, s, value): 17 | slist = list(s) 18 | for index in xrange(len(slist)): 19 | slist[index] = chr(ord(slist[index]) ^ value) 20 | return "".join(slist) 21 | 22 | def __hmacSign(self, aValue, aKey): 23 | keyb = struct.pack("%ds" % len(aKey), aKey) 24 | value = struct.pack("%ds" % len(aValue), aValue) 25 | k_ipad = self.__doXOr(keyb, 0x36) 26 | k_opad = self.__doXOr(keyb, 0x5c) 27 | k_ipad = self.__fill(k_ipad, 64, 54) 28 | k_opad = self.__fill(k_opad, 64, 92) 29 | m = hashlib.md5() 30 | m.update(k_ipad) 31 | m.update(value) 32 | dg = m.digest() 33 | 34 | m = hashlib.md5() 35 | m.update(k_opad) 36 | subStr = dg[0:16] 37 | m.update(subStr) 38 | dg = m.hexdigest() 39 | return dg 40 | 41 | def __digest(self, aValue): 42 | value = struct.pack("%ds" % len(aValue), aValue) 43 | print value 44 | h = sha.new() 45 | h.update(value) 46 | dg = h.hexdigest() 47 | return dg 48 | 49 | def __api_call(self, path, params = ''): 50 | try: 51 | SHA_secret = self.__digest(self.mysecret) 52 | sign = self.__hmacSign(params, SHA_secret) 53 | reqTime = (int)(time.time()*1000) 54 | params+= '&sign=%s&reqTime=%d'%(sign, reqTime) 55 | url = 'https://trade.zb.com/api/' + path + '?' + params 56 | request = urllib2.Request(url) 57 | response = urllib2.urlopen(request, timeout=2) 58 | doc = json.loads(response.read()) 59 | return doc 60 | except Exception,ex: 61 | print >>sys.stderr, 'zb request ex: ', ex 62 | return None 63 | 64 | def query_account(self): 65 | try: 66 | params = "accesskey="+self.mykey+"&method=getAccountInfo" 67 | path = 'getAccountInfo' 68 | 69 | obj = self.__api_call(path, params) 70 | #print obj 71 | return obj 72 | except Exception,ex: 73 | print >>sys.stderr, 'zb query_account exception,',ex 74 | return None 75 | 76 | 77 | if __name__ == '__main__': 78 | access_key = 'accesskey' 79 | access_secret = 'secretkey' 80 | 81 | api = zb_api(access_key, access_secret) 82 | 83 | print api.query_account() 84 | -------------------------------------------------------------------------------- /PYTHON/rest 接口/zb_api_python3.py: -------------------------------------------------------------------------------- 1 | __author__ = 'Ziyang' 2 | 3 | import json, hashlib,struct,time,sys 4 | import urllib.request 5 | 6 | class zb_api: 7 | 8 | def __init__(self, mykey, mysecret): 9 | self.mykey = mykey 10 | self.mysecret = mysecret 11 | self.jm = '' 12 | 13 | def __fill(self, value, lenght, fillByte): 14 | if len(value) >= lenght: 15 | return value 16 | else: 17 | fillSize = lenght - len(value) 18 | return value + chr(fillByte) * fillSize 19 | 20 | def __doXOr(self, s, value): 21 | slist = list(s.decode('utf-8')) 22 | for index in range(len(slist)): 23 | slist[index] = chr(ord(slist[index]) ^ value) 24 | return "".join(slist) 25 | 26 | def __hmacSign(self, aValue, aKey): 27 | keyb = struct.pack("%ds" % len(aKey), aKey.encode('utf-8')) 28 | value = struct.pack("%ds" % len(aValue), aValue.encode('utf-8')) 29 | k_ipad = self.__doXOr(keyb, 0x36) 30 | k_opad = self.__doXOr(keyb, 0x5c) 31 | k_ipad = self.__fill(k_ipad, 64, 54) 32 | k_opad = self.__fill(k_opad, 64, 92) 33 | m = hashlib.md5() 34 | m.update(k_ipad.encode('utf-8')) 35 | m.update(value) 36 | dg = m.digest() 37 | 38 | m = hashlib.md5() 39 | m.update(k_opad.encode('utf-8')) 40 | subStr = dg[0:16] 41 | m.update(subStr) 42 | dg = m.hexdigest() 43 | return dg 44 | 45 | def __digest(self, aValue): 46 | value = struct.pack("%ds" % len(aValue), aValue.encode('utf-8')) 47 | print(value) 48 | h = hashlib.sha1() 49 | h.update(value) 50 | dg = h.hexdigest() 51 | return dg 52 | 53 | def __api_call(self, path, params = ''): 54 | try: 55 | SHA_secret = self.__digest(self.mysecret) 56 | sign = self.__hmacSign(params, SHA_secret) 57 | self.jm = sign 58 | reqTime = (int)(time.time()*1000) 59 | params += '&sign=%s&reqTime=%d'%(sign, reqTime) 60 | url = 'https://trade.zb.com/api/' + path + '?' + params 61 | req = urllib.request.Request(url) 62 | res = urllib.request.urlopen(req, timeout=2) 63 | doc = json.loads(res.read()) 64 | return doc 65 | except Exception as ex: 66 | print(sys.stderr, 'zb request ex: ', ex) 67 | return None 68 | 69 | def query_account(self): 70 | try: 71 | params = "accesskey="+self.mykey+"&method=getAccountInfo" 72 | path = 'getAccountInfo' 73 | 74 | obj = self.__api_call(path, params) 75 | #print obj 76 | return obj 77 | except Exception as ex: 78 | print(sys.stderr, 'zb query_account exception,',ex) 79 | return None 80 | 81 | 82 | if __name__ == '__main__': 83 | access_key = 'access_key' 84 | access_secret = 'access_secret' 85 | 86 | api = zb_api(access_key, access_secret) 87 | 88 | print(api.query_account()) 89 | -------------------------------------------------------------------------------- /PYTHON/websocket 接口/readme: -------------------------------------------------------------------------------- 1 | 感谢GitHub用户:ipqhjjybj,提供的技术支持 2 | -------------------------------------------------------------------------------- /PYTHON/websocket 接口/zb.com-api-master/README.md: -------------------------------------------------------------------------------- 1 | # zb.com-api 2 | zb.com api 3 | 4 | A simple demo for zb.com .Just some useful functions. 5 |     any question contact sunxuanzhi@lingdianzn.com 6 | -------------------------------------------------------------------------------- /PYTHON/websocket 接口/zb.com-api-master/zb.comskd.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | #author:xuanzhi 4 | 5 | import requests 6 | import json 7 | import time 8 | import hashlib 9 | import hmac 10 | try: 11 | from urllib import urlencode 12 | except: 13 | from urllib.parse import urlencode 14 | 15 | 16 | 17 | 18 | BASE_API_PUBLIC = 'http://api.zb.com/data/v1' 19 | BASE_API_PRIVATE = 'https://trade.zb.com/api' 20 | 21 | DEFAULT_HEADERS = {'Content-Type': 'application/x-www-form-urlencode'} 22 | 23 | 24 | proxies = { 25 | 'https': 'http://127.0.0.1:1087', 26 | 'http': 'http://127.0.0.1:1087' 27 | } 28 | 29 | class Client_Zb(): 30 | def __init__(self, apikey, secretkey): 31 | self._public_key = str(apikey) 32 | self._private_key = str(secretkey) 33 | self.sessn = requests.Session() 34 | self.adapter = requests.adapters.HTTPAdapter(pool_connections=5, 35 | pool_maxsize=5, max_retries=5) 36 | self.sessn.mount('http://', self.adapter) 37 | self.sessn.mount('https://', self.adapter) 38 | self.order_list = [] 39 | 40 | def signature(self,message): 41 | sha_secretkey = hashlib.sha1(self._private_key.encode('utf-8')).hexdigest() 42 | signature = hmac.new(sha_secretkey.encode('utf-8'),message.encode('utf-8'),digestmod='MD5').hexdigest() # 32位md5算法进行加密签名 43 | return signature 44 | 45 | def signedRequest(self, method, path, params): 46 | 47 | # create signature: 48 | 49 | params['accesskey'] = self._public_key 50 | param = '' 51 | for key in sorted(params.keys()): 52 | #print(key) 53 | param += key + '=' + str(params.get(key)) + '&' 54 | param = param.rstrip('&') 55 | #print(param) 56 | signature = self.signature(message=param) 57 | #print(signature) 58 | params['sign'] = str(signature) 59 | params['reqTime'] = int(time.time() * 1000) 60 | #print(params) 61 | resp = self.sessn.request(method,BASE_API_PRIVATE+path,headers=DEFAULT_HEADERS,data=None,params=params,proxies=proxies) 62 | data = json.loads(resp.content) 63 | return data 64 | 65 | def ticker(self,symbol='eth_btc'): 66 | symbol = symbol.lower() 67 | if 'usd' in symbol: 68 | symbol = symbol.replace('usd','usdt') 69 | params = {'market':symbol} 70 | url = BASE_API_PUBLIC + '/ticker' 71 | #print(url) 72 | resp = requests.request("GET",url,params=params,proxies=proxies) 73 | data = json.loads(resp.text)['ticker'] 74 | return data 75 | 76 | def depth(self,symbol='eth_btc'): 77 | symbol = symbol.lower() 78 | if 'usd' in symbol: 79 | symbol = symbol.replace('usd','usdt') 80 | params = {'market':symbol} 81 | url = BASE_API_PUBLIC + '/depth' 82 | resp = requests.request("GET",url,params=params,proxies=proxies) 83 | data = json.loads(resp.text) 84 | temp = {'asks':data['asks'][::-1],'bids':data['bids']} 85 | return temp 86 | 87 | def balance(self): 88 | params = {'method':'getAccountInfo'} 89 | resp = self.signedRequest(method="GET",path ='/getAccountInfo',params=params)['result']['coins'] 90 | avalible,frozen,total = {},{},{} 91 | for item in resp: 92 | coin = item['enName'] 93 | avalible[coin] = float(item['available']) 94 | frozen[coin] = float(item['freez']) 95 | total[coin] = avalible[coin] + frozen[coin] 96 | temp = {'total':total,'avalible':avalible,'frozen':frozen} 97 | return temp 98 | 99 | def trade(self,trade_type,price,amount,symbol): 100 | ''' 101 | 只存在限价买卖,limit_buy/limit_sell 102 | 对于成功的订单,返回该订单号,并将其存入订单列表,以便后续的查看与撤单 103 | 104 | ''' 105 | symbol = symbol.lower() 106 | if 'usd' in symbol: 107 | symbol = symbol.replace('usd','usdt') 108 | params = {'method':'order'} 109 | order_type,side = trade_type.split('_') 110 | params = {'currency':symbol,'price':price,'amount':amount} 111 | if order_type == 'limit': 112 | if side == 'buy': 113 | params['tradeType'] = 1 114 | elif side == 'sell': 115 | params['tradeType'] = 0 116 | else: 117 | print('下单错误!!!') 118 | resp = self.signedRequest(method="GET",path ='/order',params=params) 119 | if resp['code'] == 1000: 120 | return resp['id'] 121 | self.order_list.append(resp['id']) 122 | else: 123 | print('下单失败!!!') 124 | 125 | 126 | def order_info(self,symbol,order_id): 127 | symbol = symbol.lower() 128 | if 'usd' in symbol: 129 | symbol = symbol.replace('usd','usdt') 130 | params = {'id':order_id,'currency':symbol,'method':'getOrder'} 131 | resp = self.signedRequest(method="GET",path ='/getOrder',params=params) 132 | return resp 133 | 134 | def cancel_order(self,symbol,order_id): 135 | ''' 136 | 传入订单Id与交易对,如撤单成功则打印‘撤单成功’,如撤单失败则打印撤单失败并返回失败的Id 137 | ''' 138 | symbol = symbol.lower() 139 | if 'usd' in symbol: 140 | symbol = symbol.replace('usd','usdt') 141 | params = {'id':order_id,'currency':symbol,'method':'ancelOrder'} 142 | resp = self.signedRequest(method="GET",path ='/cancelOrder',params=params) 143 | if resp['code'] == 1000: 144 | print('撤单成功: ',order_id) 145 | self.order_list.remove(order_id) 146 | else: 147 | print('撤单失败: ',order_id) 148 | return order_id 149 | 150 | def cancel_all(self): 151 | ''' 152 | 返回所有处理过的订单id,无论成功失败。 153 | ''' 154 | orderid_list=self.order_list 155 | processed_id = [] 156 | for i in orderid_list: 157 | processed_id.append(cancel_order(i)) 158 | return processed_id 159 | 160 | def open_orders(self,symbol,side,pageIndex=1): 161 | ''' 162 | 获取多个委托买单或卖单,每次请求返回10条记录 163 | side: 可选 buy 1 /sell 0 164 | pageIndex:记录页数 165 | ''' 166 | symbol = symbol.lower() 167 | if 'usd' in symbol: 168 | symbol = symbol.replace('usd','usdt') 169 | params = {'currency':symbol,'tradeType':side,'pageIndex':pageIndex,'method':'getOrdersNew'} 170 | resp = self.signedRequest(method="GET",path='/getOrdersNew',params=params) 171 | return resp 172 | 173 | apikey = '' 174 | secretkey = '' 175 | client = Client_Zb(apikey,secretkey) 176 | #print(client.ticker()) 177 | #print(client.depth()) 178 | print(client.balance()) 179 | #print(client.open_orders('eth_btc','buy')) 180 | 181 | -------------------------------------------------------------------------------- /PYTHON/websocket 接口/zb_py_socket/reame.txt: -------------------------------------------------------------------------------- 1 | API 文档地址 2 | https://www.zb.com/i/developer/websocketApi#config 3 | 4 | 代码 描述 5 | 1000 调用成功 6 | 1001 一般错误提示 7 | 1002 内部错误 8 | 1003 验证不通过 9 | 1004 资金安全密码锁定 10 | 1005 资金安全密码错误,请确认后重新输入。 11 | 1006 实名认证等待审核或审核不通过 12 | 1007 频道为空 13 | 1008 事件为空 14 | 1009 此接口维护中 15 | 2001 人民币账户余额不足 16 | 2002 比特币账户余额不足 17 | 2003 莱特币账户余额不足 18 | 2005 以太币账户余额不足 19 | 2006 ETC币账户余额不足 20 | 2007 BTS币账户余额不足 21 | 2008 EOS币账户余额不足 22 | 2009 账户余额不足 23 | 3001 挂单没有找到 24 | 3002 无效的金额 25 | 3003 无效的数量 26 | 3004 用户不存在 27 | 3005 无效的参数 28 | 3006 无效的IP或与绑定的IP不一致 29 | 3007 请求时间已失效 30 | 3008 交易记录没有找到 31 | 4001 API接口被锁定或未启用 32 | 4002 请求过于频繁 33 | 34 | 35 | WebSocket服务地址 36 | ZB WebSocket服务连接地址:wss://api.zb.com:9999/websocket 37 | 38 | 接口 描述 39 | ticker行情 40 | depth市场深度 41 | trades历史成交 42 | 交易API 43 | 44 | 用于ZB快速进行交易 45 | 46 | 接口 描述 47 | order委托下单 48 | cancelOrder取消委托 49 | getOrder获取委托买单或卖单 50 | getorders获取多个委托买单或卖单,每次请求返回10条记录 51 | getordersignoretradetype取消tradeType字段过滤,可同时获取买单和卖单,每次请求返回pageSize<100条记录 52 | getaccountinfo获取用户信息 53 | 54 | -------------------------------------------------------------------------------- /PYTHON/websocket 接口/zb_py_socket/test.py: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | 3 | from vnzb import * 4 | 5 | # 在zb网站申请这两个Key 6 | apiKey = 'apiKey' 7 | secretKey = 'secretKey' 8 | 9 | # 创建API对象 10 | api = ZB_Sub_Spot_Api() 11 | 12 | api.connect_Subpot(apiKey, secretKey, True) 13 | 14 | sleep(3) 15 | 16 | # api.login() 17 | # api.subscribeSpotTicker("ltc_btc") 18 | # api.subscribeSpotDepth("ltc_btc") 19 | # api.subscribeSpotTrades("ltc_btc") 20 | #api.subscribeSpotKlines("bch_btc","30min") 21 | 22 | #api.spotTrade("btc_qc", 1 , "50" , "0.01") 23 | ''' 24 | {"message":"操作成功","no":"0","data":"{entrustId:2017121051685}","code":1000,"channel":"btcqc_order","success":true} 25 | {"message":"操作成功","no":"0","data":"{entrustId:2017121051713}","code":1000,"channel":"btcqc_order","success":true} 26 | ''' 27 | #api.spotUserInfo() 28 | 29 | #api.spotCancelOrder("btc_qc", "2017121051685") 30 | 31 | api.spotOrderInfo("btc_qc","2017121051713") 32 | -------------------------------------------------------------------------------- /PYTHON/websocket 接口/zb_py_socket/test.py.bak: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | 3 | from vnzb import * 4 | 5 | # 在ZB网站申请这两个Key,分别对应用户名和密码 6 | apiKey = 'apiKey' 7 | secretKey = 'secretKey' 8 | 9 | # 创建API对象 10 | api = ZB_Sub_Spot_Api() 11 | 12 | api.connect_Subpot(apiKey, secretKey, True) 13 | 14 | sleep(3) 15 | 16 | # api.login() 17 | # api.subscribeSpotTicker("ltc_btc") 18 | # api.subscribeSpotDepth("ltc_btc") 19 | # api.subscribeSpotTrades("ltc_btc") 20 | #api.subscribeSpotKlines("bch_btc","30min") 21 | 22 | #api.spotTrade("btc_qc", 1 , "50" , "0.01") 23 | ''' 24 | {"message":"操作成功","no":"0","data":"{entrustId:2017121051685}","code":1000,"channel":"btcqc_order","success":true} 25 | {"message":"操作成功","no":"0","data":"{entrustId:2017121051713}","code":1000,"channel":"btcqc_order","success":true} 26 | ''' 27 | #api.spotUserInfo() 28 | 29 | #api.spotCancelOrder("btc_qc", "2017121051685") 30 | 31 | api.spotOrderInfo("btc_qc","2017121051713") 32 | -------------------------------------------------------------------------------- /PYTHON/websocket 接口/zb_py_socket/vnzb.py: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | 3 | import hashlib 4 | import zlib 5 | import json 6 | from time import sleep 7 | from threading import Thread 8 | 9 | import websocket 10 | import urllib2, hashlib,struct,sha,time 11 | 12 | 13 | zb_usd_url = "wss://api.zb.com:9999/websocket" 14 | zb_all_symbols = ["ltc_btc"] 15 | 16 | class ZB_Sub_Spot_Api(object): 17 | """基于Websocket的API对象""" 18 | def __init__(self): 19 | """Constructor""" 20 | self.apiKey = '' # apiKey 21 | self.secretKey = '' # secretKey 22 | 23 | self.ws_sub_spot = None # websocket应用对象 现货对象 24 | 25 | #---------------------------------------------------------------------- 26 | def reconnect(self): 27 | """重新连接""" 28 | # 首先关闭之前的连接 29 | self.close() 30 | 31 | # 再执行重连任务 32 | self.ws_sub_spot = websocket.WebSocketApp(self.host, 33 | on_message=self.onMessage, 34 | on_error=self.onError, 35 | on_close=self.onClose, 36 | on_open=self.onOpen) 37 | 38 | self.thread = Thread(target=self.ws_sub_spot.run_forever) 39 | self.thread.start() 40 | 41 | #---------------------------------------------------------------------- 42 | def connect_Subpot(self, apiKey , secretKey , trace = False): 43 | self.host = zb_usd_url 44 | self.apiKey = apiKey 45 | self.secretKey = secretKey 46 | 47 | websocket.enableTrace(trace) 48 | 49 | self.ws_sub_spot = websocket.WebSocketApp(self.host, 50 | on_message=self.onMessage, 51 | on_error=self.onError, 52 | on_close=self.onClose, 53 | on_open=self.onOpen) 54 | 55 | self.thread = Thread(target=self.ws_sub_spot.run_forever) 56 | self.thread.start() 57 | 58 | #---------------------------------------------------------------------- 59 | def readData(self, evt): 60 | """解压缩推送收到的数据""" 61 | # # 创建解压器 62 | # decompress = zlib.decompressobj(-zlib.MAX_WBITS) 63 | 64 | # # 将原始数据解压成字符串 65 | # inflated = decompress.decompress(evt) + decompress.flush() 66 | 67 | # 通过json解析字符串 68 | data = json.loads(evt) 69 | 70 | return data 71 | 72 | #---------------------------------------------------------------------- 73 | def close(self): 74 | """关闭接口""" 75 | if self.thread and self.thread.isAlive(): 76 | self.ws_sub_spot.close() 77 | self.thread.join() 78 | 79 | #---------------------------------------------------------------------- 80 | def onMessage(self, ws, evt): 81 | """信息推送""" 82 | print evt 83 | 84 | #---------------------------------------------------------------------- 85 | def onError(self, ws, evt): 86 | """错误推送""" 87 | print 'onError' 88 | print evt 89 | 90 | #---------------------------------------------------------------------- 91 | def onClose(self, ws): 92 | """接口断开""" 93 | print 'onClose' 94 | 95 | #---------------------------------------------------------------------- 96 | def onOpen(self, ws): 97 | """接口打开""" 98 | print 'onOpen' 99 | 100 | #---------------------------------------------------------------------- 101 | def subscribeSpotTicker(self, symbol_pair): 102 | # 现货的 ticker 103 | symbol_pair = symbol_pair.replace('_','') 104 | req = "{'event':'addChannel','channel':'%s_ticker'}" % symbol_pair 105 | self.ws_sub_spot.send(req) 106 | 107 | #---------------------------------------------------------------------- 108 | def subscribeSpotDepth(self, symbol_pair): 109 | # 现货的 市场深度 110 | symbol_pair = symbol_pair.replace('_','') 111 | req = "{'event':'addChannel','channel':'%s_depth'}" % symbol_pair 112 | self.ws_sub_spot.send(req) 113 | 114 | #---------------------------------------------------------------------- 115 | def subscribeSpotTrades(self, symbol_pair): 116 | symbol_pair = symbol_pair.replace('_','') 117 | req = "{'event':'addChannel','channel':'%s_trades'}" % symbol_pair 118 | self.ws_sub_spot.send(req) 119 | 120 | #---------------------------------------------------------------------- 121 | def __fill(self, value, lenght, fillByte): 122 | if len(value) >= lenght: 123 | return value 124 | else: 125 | fillSize = lenght - len(value) 126 | return value + chr(fillByte) * fillSize 127 | #---------------------------------------------------------------------- 128 | def __doXOr(self, s, value): 129 | slist = list(s) 130 | for index in xrange(len(slist)): 131 | slist[index] = chr(ord(slist[index]) ^ value) 132 | return "".join(slist) 133 | #---------------------------------------------------------------------- 134 | def __hmacSign(self, aValue, aKey): 135 | keyb = struct.pack("%ds" % len(aKey), aKey) 136 | value = struct.pack("%ds" % len(aValue), aValue) 137 | k_ipad = self.__doXOr(keyb, 0x36) 138 | k_opad = self.__doXOr(keyb, 0x5c) 139 | k_ipad = self.__fill(k_ipad, 64, 54) 140 | k_opad = self.__fill(k_opad, 64, 92) 141 | m = hashlib.md5() 142 | m.update(k_ipad) 143 | m.update(value) 144 | dg = m.digest() 145 | 146 | m = hashlib.md5() 147 | m.update(k_opad) 148 | subStr = dg[0:16] 149 | m.update(subStr) 150 | dg = m.hexdigest() 151 | return dg 152 | 153 | #---------------------------------------------------------------------- 154 | def __digest(self, aValue): 155 | value = struct.pack("%ds" % len(aValue), aValue) 156 | h = sha.new() 157 | h.update(value) 158 | dg = h.hexdigest() 159 | return dg 160 | 161 | #---------------------------------------------------------------------- 162 | def generateSign(self, params): 163 | """生成签名""" 164 | ''' 165 | {"accesskey":"0f39fb8b-d95d-4afe-b2a9-94f5f4d9fdb5","channel":"getaccountinfo","event":"addChannel"} 166 | ''' 167 | l = [] 168 | for key in sorted(params.keys()): 169 | l.append('"%s":"%s"' %(key, params[key])) 170 | sign = ','.join(l) 171 | sign = '{' + sign + '}' 172 | 173 | SHA_secret = self.__digest(self.secretKey) 174 | return self.__hmacSign( sign, SHA_secret) 175 | # return hashlib.md5(sign.encode('utf-8')).hexdigest().upper() 176 | 177 | #---------------------------------------------------------------------- 178 | def sendTradingRequest(self, channel, params): 179 | """发送交易请求""" 180 | # 在参数字典中加上api_key和签名字段 181 | params['accesskey'] = self.apiKey 182 | params['channel'] = channel 183 | params['event'] = "addChannel" 184 | 185 | params['sign'] = self.generateSign(params) 186 | 187 | # 使用json打包并发送 188 | j = json.dumps(params) 189 | 190 | # 若触发异常则重连 191 | try: 192 | self.ws_sub_spot.send(j) 193 | except websocket.WebSocketConnectionClosedException: 194 | pass 195 | 196 | #---------------------------------------------------------------------- 197 | def spotTrade(self, symbol_pair, type_, price, amount): 198 | """现货委托""" 199 | symbol_pair = symbol_pair.replace('_','') 200 | params = {} 201 | params['tradeType'] = str(type_) 202 | params['price'] = str(price) 203 | params['amount'] = str(amount) 204 | 205 | channel = symbol_pair.lower() + "_order" 206 | 207 | self.sendTradingRequest(channel, params) 208 | 209 | #---------------------------------------------------------------------- 210 | def spotCancelOrder(self, symbol_pair, orderid): 211 | """现货撤单""" 212 | symbol_pair = symbol_pair.replace('_','') 213 | params = {} 214 | params['id'] = str(orderid) 215 | 216 | channel = symbol_pair.lower() + "_cancelorder" 217 | 218 | self.sendTradingRequest(channel, params) 219 | 220 | #---------------------------------------------------------------------- 221 | def spotUserInfo(self): 222 | """查询现货账户""" 223 | channel = 'getaccountinfo' 224 | self.sendTradingRequest(channel, {}) 225 | 226 | #---------------------------------------------------------------------- 227 | def spotOrderInfo(self, symbol_pair, orderid): 228 | """查询现货委托信息""" 229 | symbol_pair = symbol_pair.replace('_','') 230 | params = {} 231 | params['id'] = str(orderid) 232 | 233 | channel = symbol_pair.lower() + "_getorder" 234 | 235 | self.sendTradingRequest(channel, params) 236 | 237 | #---------------------------------------------------------------------- 238 | def spotGetOrders(self, symbol_pair , orderid): 239 | pass 240 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # api 2 | ## 加密方式 https://gitee.com/lianlianyi/zb-api/blob/master/%E5%8A%A0%E5%AF%86.md 3 | 4 | ## java 模块化demo : https://gitee.com/lianlianyi/zb-api 5 | 6 | ## 感谢GitHub用户(ipqhjjybj)提供项目zb_py_socket 的技术支持 7 | 8 | ## 感谢开发者 小鱼(QQ和微信:49744774) 提供项目 易语言中币api示例 的技术支持 9 | 10 | ## 感谢开发者 闫瑾瑾闫(QQ:729977187) 提供项目 python项目zb.com-api-master.zip 11 | 12 | -------------------------------------------------------------------------------- /golang/zb-api-trade-master.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zb2017/api/4927d6940c9f217c91b11c042532827897f74927/golang/zb-api-trade-master.zip -------------------------------------------------------------------------------- /zb_api_rest_java/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /zb_api_rest_java/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | zb_api_rest_demo 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.wst.common.project.facet.core.builder 15 | 16 | 17 | 18 | 19 | org.eclipse.wst.validation.validationbuilder 20 | 21 | 22 | 23 | 24 | org.eclipse.m2e.core.maven2Builder 25 | 26 | 27 | 28 | 29 | 30 | org.eclipse.jem.workbench.JavaEMFNature 31 | org.eclipse.wst.common.modulecore.ModuleCoreNature 32 | org.eclipse.jdt.core.javanature 33 | org.eclipse.m2e.core.maven2Nature 34 | org.eclipse.wst.common.project.facet.core.nature 35 | org.eclipse.wst.jsdt.core.jsNature 36 | 37 | 38 | -------------------------------------------------------------------------------- /zb_api_rest_java/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | rest.api.exx 5 | exx_api_rest_demo 6 | 0.0.1-SNAPSHOT 7 | war 8 | 9 | 10 | UTF-8 11 | 12 | 13 | 14 | junit 15 | junit 16 | 4.8 17 | test 18 | 19 | 20 | log4j 21 | log4j 22 | 1.2.16 23 | 24 | 25 | com.alibaba 26 | fastjson 27 | 1.2.31 28 | 29 | 30 | 31 | org.apache.httpcomponents 32 | httpcore 33 | 4.4 34 | 35 | 36 | org.apache.httpcomponents 37 | httpclient 38 | 4.4 39 | 40 | 41 | commons-io 42 | commons-io 43 | 2.5 44 | 45 | 46 | 47 | 48 | exx_api_rest_demo 49 | 50 | -------------------------------------------------------------------------------- /zb_api_rest_java/src/main/java/com/zb/kits/EncryDigestUtil.java: -------------------------------------------------------------------------------- 1 | package com.zb.kits; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | import java.math.BigInteger; 5 | import java.security.InvalidKeyException; 6 | import java.security.MessageDigest; 7 | import java.security.NoSuchAlgorithmException; 8 | import java.util.Arrays; 9 | 10 | import javax.crypto.Mac; 11 | import javax.crypto.spec.SecretKeySpec; 12 | 13 | public class EncryDigestUtil { 14 | 15 | private static String encodingCharset = "UTF-8"; 16 | 17 | 18 | public static String hmacSign(String aValue, String aKey) { 19 | return hmacSign(aValue, aKey , "MD5"); 20 | } 21 | 22 | /** 23 | * 生成签名消息 24 | * @param aValue 要签名的字符串 25 | * @param aKey 签名密钥 26 | * @return 27 | */ 28 | public static String hmacSign(String aValue, String aKey,String jiami) { 29 | byte k_ipad[] = new byte[64]; 30 | byte k_opad[] = new byte[64]; 31 | byte keyb[]; 32 | byte value[]; 33 | try { 34 | keyb = aKey.getBytes(encodingCharset); 35 | value = aValue.getBytes(encodingCharset); 36 | } catch (UnsupportedEncodingException e) { 37 | keyb = aKey.getBytes(); 38 | value = aValue.getBytes(); 39 | } 40 | 41 | Arrays.fill(k_ipad, keyb.length, 64, (byte) 54); 42 | Arrays.fill(k_opad, keyb.length, 64, (byte) 92); 43 | for (int i = 0; i < keyb.length; i++) { 44 | k_ipad[i] = (byte) (keyb[i] ^ 0x36); 45 | k_opad[i] = (byte) (keyb[i] ^ 0x5c); 46 | } 47 | 48 | MessageDigest md = null; 49 | try { 50 | md = MessageDigest.getInstance(jiami);//"MD5" 51 | } catch (NoSuchAlgorithmException e) { 52 | 53 | return null; 54 | } 55 | md.update(k_ipad); 56 | md.update(value); 57 | byte dg[] = md.digest(); 58 | md.reset(); 59 | md.update(k_opad); 60 | md.update(dg, 0, 16); 61 | dg = md.digest(); 62 | return toHex(dg); 63 | } 64 | 65 | /*** 66 | * 对应python里面的hmac.new(API_SECRET, msg=message, digestmod=hashlib.sha256).hexdigest().upper() 67 | * @param key 68 | * @param value 69 | * @return 70 | */ 71 | public static String hamacSha256(String key , String value){ 72 | String result = null; 73 | byte[] keyBytes = key.getBytes(); 74 | SecretKeySpec localMac = new SecretKeySpec(keyBytes, "HmacSHA256"); 75 | try { 76 | Mac mac = Mac.getInstance("HmacSHA256"); 77 | mac.init(localMac); 78 | byte[] arrayOfByte = mac.doFinal(value.getBytes()); 79 | BigInteger localBigInteger = new BigInteger(1, 80 | arrayOfByte); 81 | result = String.format("%0" + (arrayOfByte.length << 1) + "x", 82 | new Object[] { localBigInteger }); 83 | 84 | } catch (InvalidKeyException e) { 85 | e.printStackTrace(); 86 | } catch (NoSuchAlgorithmException e) { 87 | e.printStackTrace(); 88 | } catch (IllegalStateException e) { 89 | e.printStackTrace(); 90 | } 91 | 92 | return result; 93 | } 94 | 95 | public static String toHex(byte input[]) { 96 | if (input == null) 97 | return null; 98 | StringBuffer output = new StringBuffer(input.length * 2); 99 | for (int i = 0; i < input.length; i++) { 100 | int current = input[i] & 0xff; 101 | if (current < 16) 102 | output.append("0"); 103 | output.append(Integer.toString(current, 16)); 104 | } 105 | 106 | return output.toString(); 107 | } 108 | 109 | /** 110 | * 111 | * @param args 112 | * @param key 113 | * @return 114 | */ 115 | public static String getHmac(String[] args, String key) { 116 | if (args == null || args.length == 0) { 117 | return (null); 118 | } 119 | StringBuffer str = new StringBuffer(); 120 | for (int i = 0; i < args.length; i++) { 121 | str.append(args[i]); 122 | } 123 | return (hmacSign(str.toString(), key)); 124 | } 125 | 126 | /** 127 | * SHA加密 128 | * @param aValue 129 | * @return 130 | */ 131 | public static String digest(String aValue , String algorithm) { 132 | aValue = aValue.trim(); 133 | byte value[]; 134 | try { 135 | value = aValue.getBytes(encodingCharset); 136 | } catch (UnsupportedEncodingException e) { 137 | value = aValue.getBytes(); 138 | } 139 | MessageDigest md = null; 140 | try { 141 | md = MessageDigest.getInstance("SHA"); 142 | } catch (NoSuchAlgorithmException e) { 143 | e.printStackTrace(); 144 | return null; 145 | } 146 | return toHex(md.digest(value)); 147 | 148 | } 149 | 150 | /*** 151 | * sha-1散列加密 152 | * @param aValue 153 | * @return 154 | */ 155 | public static String digest(String aValue) { 156 | return digest(aValue, "SHA"); 157 | } 158 | /*** 159 | * sha-256散列加密 160 | * @param aValue 161 | * @return 162 | */ 163 | public static String digestSha256(String aValue) { 164 | return digest(aValue, "SHA-256"); 165 | } 166 | 167 | public static void main(String[] args) { 168 | // System.out.println(digest("mima123465")); 169 | System.out.println(hmacSign("method=getAccountInfo&accesskey=826afc09-58e5-4ebc-b31c-64956082c705", digest("ab391be1-c1a1-4252-83fc-8b358bd72252"))); 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /zb_api_rest_java/src/main/java/com/zb/kits/HttpUtilManager.java: -------------------------------------------------------------------------------- 1 | package com.zb.kits; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.security.KeyManagementException; 6 | import java.security.NoSuchAlgorithmException; 7 | import java.util.ArrayList; 8 | import java.util.LinkedList; 9 | import java.util.List; 10 | import java.util.Map; 11 | import java.util.Map.Entry; 12 | import java.util.concurrent.TimeUnit; 13 | 14 | import javax.net.ssl.SSLContext; 15 | import javax.net.ssl.TrustManager; 16 | import javax.net.ssl.X509TrustManager; 17 | 18 | import org.apache.commons.io.IOUtils; 19 | import org.apache.http.Consts; 20 | import org.apache.http.HttpEntity; 21 | import org.apache.http.HttpException; 22 | import org.apache.http.HttpResponse; 23 | import org.apache.http.NameValuePair; 24 | import org.apache.http.client.ClientProtocolException; 25 | import org.apache.http.client.HttpClient; 26 | import org.apache.http.client.config.RequestConfig; 27 | import org.apache.http.client.entity.UrlEncodedFormEntity; 28 | import org.apache.http.client.methods.CloseableHttpResponse; 29 | import org.apache.http.client.methods.HttpGet; 30 | import org.apache.http.client.methods.HttpPost; 31 | import org.apache.http.client.methods.HttpRequestBase; 32 | import org.apache.http.config.Registry; 33 | import org.apache.http.config.RegistryBuilder; 34 | import org.apache.http.conn.ConnectionKeepAliveStrategy; 35 | import org.apache.http.conn.socket.ConnectionSocketFactory; 36 | import org.apache.http.conn.socket.PlainConnectionSocketFactory; 37 | import org.apache.http.conn.ssl.SSLConnectionSocketFactory; 38 | import org.apache.http.impl.client.CloseableHttpClient; 39 | import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy; 40 | import org.apache.http.impl.client.HttpClients; 41 | import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; 42 | import org.apache.http.message.BasicNameValuePair; 43 | import org.apache.http.protocol.HttpContext; 44 | import org.apache.http.util.EntityUtils; 45 | 46 | /** 47 | * 封装HTTP get post请求,简化发送http请求 48 | * 49 | * @author zhangchi 50 | * 51 | */ 52 | public class HttpUtilManager { 53 | 54 | private static HttpUtilManager instance = new HttpUtilManager(); 55 | private static HttpClient client; 56 | private static long startTime = System.currentTimeMillis(); 57 | public static PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(); 58 | private static ConnectionKeepAliveStrategy keepAliveStrat = new DefaultConnectionKeepAliveStrategy() { 59 | public long getKeepAliveDuration(HttpResponse response, HttpContext context) { 60 | long keepAlive = super.getKeepAliveDuration(response, context); 61 | 62 | if (keepAlive == -1) { 63 | keepAlive = 5000; 64 | } 65 | return keepAlive; 66 | } 67 | 68 | }; 69 | 70 | private HttpUtilManager() { 71 | client = HttpClients.custom().setConnectionManager(cm).setKeepAliveStrategy(keepAliveStrat).build(); 72 | } 73 | 74 | public static void IdleConnectionMonitor() { 75 | 76 | if (System.currentTimeMillis() - startTime > 30000) { 77 | startTime = System.currentTimeMillis(); 78 | cm.closeExpiredConnections(); 79 | cm.closeIdleConnections(30, TimeUnit.SECONDS); 80 | } 81 | } 82 | 83 | private static RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(20000).setConnectTimeout(20000) 84 | .setConnectionRequestTimeout(20000).build(); 85 | 86 | public static HttpUtilManager getInstance() { 87 | return instance; 88 | } 89 | 90 | public HttpClient getHttpClient() { 91 | return client; 92 | } 93 | 94 | private HttpPost httpPostMethod(String url) { 95 | return new HttpPost(url); 96 | } 97 | 98 | private HttpRequestBase httpGetMethod(String url) { 99 | return new HttpGet(url); 100 | } 101 | 102 | public HttpResponse getResponse(String url) throws ClientProtocolException, IOException { 103 | IdleConnectionMonitor(); 104 | HttpRequestBase method = this.httpGetMethod(url); 105 | 106 | method.setConfig(requestConfig); 107 | HttpResponse response = client.execute(method); 108 | return response; 109 | } 110 | 111 | public String requestHttpGet(String url, Map params) throws HttpException, IOException { 112 | List keys = new ArrayList(params.keySet()); 113 | String pas = ""; 114 | if (!keys.isEmpty()) { 115 | int keySize = keys.size(); 116 | for (int i = 0; i < keySize; i++) { 117 | String key = keys.get(i); 118 | String value = params.get(key); 119 | pas += key + "=" + value + "&"; 120 | } 121 | pas = pas.substring(0, pas.length() - 1); 122 | } 123 | return this.requestHttpGet(url, "", pas); 124 | } 125 | 126 | /** 127 | * 绕过验证 128 | * 129 | * @return 130 | * @throws NoSuchAlgorithmException 131 | * @throws KeyManagementException 132 | */ 133 | public static SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException { 134 | SSLContext sc = SSLContext.getInstance("SSLv3"); 135 | 136 | // 实现一个X509TrustManager接口,用于绕过验证,不用修改里面的方法 137 | X509TrustManager trustManager = new X509TrustManager() { 138 | 139 | public void checkClientTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate, 140 | String paramString) { 141 | } 142 | 143 | public void checkServerTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate, 144 | String paramString) { 145 | } 146 | 147 | public java.security.cert.X509Certificate[] getAcceptedIssuers() { 148 | return null; 149 | } 150 | }; 151 | 152 | sc.init(null, new TrustManager[] { trustManager }, null); 153 | return sc; 154 | } 155 | 156 | /** 157 | * 模拟请求 158 | * 159 | * @param url 160 | * 资源地址 161 | * @param map 162 | * 参数列表 163 | * @param encoding 164 | * 编码 165 | * @return 166 | * @throws NoSuchAlgorithmException 167 | * @throws KeyManagementException 168 | * @throws IOException 169 | * @throws ClientProtocolException 170 | */ 171 | public static String sendHttps(String url, Map map, String encoding) { 172 | String body = ""; 173 | // 采用绕过验证的方式处理https请求 174 | SSLContext sslcontext; 175 | try { 176 | sslcontext = createIgnoreVerifySSL(); 177 | // 设置协议http和https对应的处理socket链接工厂的对象 178 | Registry socketFactoryRegistry = RegistryBuilder.create() 179 | .register("http", PlainConnectionSocketFactory.INSTANCE) 180 | .register("https", new SSLConnectionSocketFactory(sslcontext)).build(); 181 | PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager( 182 | socketFactoryRegistry); 183 | HttpClients.custom().setConnectionManager(connManager); 184 | 185 | // 创建自定义的httpclient对象 186 | CloseableHttpClient client = HttpClients.custom().setConnectionManager(connManager).build(); 187 | // CloseableHttpClient client = HttpClients.createDefault(); 188 | 189 | // 创建post方式请求对象 190 | HttpPost httpPost = new HttpPost(url); 191 | 192 | // 装填参数 193 | List nvps = new ArrayList(); 194 | if (map != null) { 195 | for (Entry entry : map.entrySet()) { 196 | nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue())); 197 | } 198 | } 199 | // 设置参数到请求对象中 200 | httpPost.setEntity(new UrlEncodedFormEntity(nvps, encoding)); 201 | 202 | System.out.println("请求地址:" + url); 203 | System.out.println("请求参数:" + nvps.toString()); 204 | 205 | // 设置header信息 206 | // 指定报文头【Content-type】、【User-Agent】 207 | httpPost.setHeader("Content-type", "application/x-www-form-urlencoded"); 208 | httpPost.setHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)"); 209 | 210 | // 执行请求操作,并拿到结果(同步阻塞) 211 | CloseableHttpResponse response = client.execute(httpPost); 212 | // 获取结果实体 213 | HttpEntity entity = response.getEntity(); 214 | if (entity != null) { 215 | // 按指定编码转换结果实体为String类型 216 | body = EntityUtils.toString(entity, encoding); 217 | } 218 | EntityUtils.consume(entity); 219 | // 释放链接 220 | response.close(); 221 | } catch (KeyManagementException | NoSuchAlgorithmException e) { 222 | // TODO Auto-generated catch block 223 | e.printStackTrace(); 224 | } catch (IOException e) { 225 | // TODO Auto-generated catch block 226 | e.printStackTrace(); 227 | } 228 | 229 | return body; 230 | } 231 | 232 | public String requestHttpGet(String url_prex, String url, String param) throws HttpException, IOException { 233 | 234 | IdleConnectionMonitor(); 235 | url = url_prex + url; 236 | if (param != null && !param.equals("")) { 237 | if (url.endsWith("?")) { 238 | url = url + param; 239 | } else { 240 | url = url + "?" + param; 241 | } 242 | } 243 | HttpRequestBase method = this.httpGetMethod(url); 244 | method.setConfig(requestConfig); 245 | HttpResponse response = client.execute(method); 246 | 247 | HttpEntity entity = response.getEntity(); 248 | if (entity == null) { 249 | return ""; 250 | } 251 | InputStream is = null; 252 | String responseData = ""; 253 | try { 254 | is = entity.getContent(); 255 | responseData = IOUtils.toString(is, "UTF-8"); 256 | } finally { 257 | if (is != null) { 258 | is.close(); 259 | } 260 | } 261 | // System.out.println(responseData); 262 | return responseData; 263 | } 264 | 265 | public String requestHttpPost(String url_prex, String url, Map params) 266 | throws HttpException, IOException { 267 | IdleConnectionMonitor(); 268 | url = url_prex + url; 269 | HttpPost method = this.httpPostMethod(url); 270 | List valuePairs = this.convertMap2PostParams(params); 271 | UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(valuePairs, Consts.UTF_8); 272 | method.setEntity(urlEncodedFormEntity); 273 | method.setConfig(requestConfig); 274 | HttpResponse response = client.execute(method); 275 | // System.out.println(method.getURI()); 276 | HttpEntity entity = response.getEntity(); 277 | 278 | if (entity == null) { 279 | return ""; 280 | } 281 | InputStream is = null; 282 | String responseData = ""; 283 | try { 284 | is = entity.getContent(); 285 | responseData = IOUtils.toString(is, "UTF-8"); 286 | } finally { 287 | if (is != null) { 288 | is.close(); 289 | } 290 | } 291 | return responseData; 292 | 293 | } 294 | 295 | private List convertMap2PostParams(Map params) { 296 | List keys = new ArrayList(params.keySet()); 297 | if (keys.isEmpty()) { 298 | return null; 299 | } 300 | int keySize = keys.size(); 301 | List data = new LinkedList(); 302 | for (int i = 0; i < keySize; i++) { 303 | String key = keys.get(i); 304 | String value = params.get(key); 305 | data.add(new BasicNameValuePair(key, value)); 306 | } 307 | return data; 308 | } 309 | 310 | } 311 | -------------------------------------------------------------------------------- /zb_api_rest_java/src/main/java/com/zb/kits/JsonFormatTool.java: -------------------------------------------------------------------------------- 1 | package com.zb.kits; 2 | 3 | import java.util.ArrayList; 4 | 5 | public class JsonFormatTool { 6 | /** 7 | * json字符串的格式化 8 | * @author peiyuxin 9 | * @param json 需要格式的json串 10 | * @param fillStringUnit每一层之前的占位符号比如空格 制表符 11 | * @return 12 | */ 13 | public static String formatJson(String json, String fillStringUnit) { 14 | if (json == null || json.trim().length() == 0) { 15 | return null; 16 | } 17 | 18 | int fixedLenth = 0; 19 | ArrayList tokenList = new ArrayList(); 20 | { 21 | String jsonTemp = json; 22 | //预读取 23 | while (jsonTemp.length() > 0) { 24 | String token = getToken(jsonTemp); 25 | jsonTemp = jsonTemp.substring(token.length()); 26 | token = token.trim(); 27 | tokenList.add(token); 28 | } 29 | } 30 | 31 | for (int i = 0; i < tokenList.size(); i++) { 32 | String token = tokenList.get(i); 33 | int length = token.getBytes().length; 34 | if (length > fixedLenth && i < tokenList.size() - 1 && tokenList.get(i + 1).equals(":")) { 35 | fixedLenth = length; 36 | } 37 | } 38 | 39 | StringBuilder buf = new StringBuilder(); 40 | int count = 0; 41 | for (int i = 0; i < tokenList.size(); i++) { 42 | 43 | String token = tokenList.get(i); 44 | 45 | if (token.equals(",")) { 46 | buf.append(token); 47 | doFill(buf, count, fillStringUnit); 48 | continue; 49 | } 50 | if (token.equals(":")) { 51 | buf.append(" ").append(token).append(" "); 52 | continue; 53 | } 54 | if (token.equals("{")) { 55 | String nextToken = tokenList.get(i + 1); 56 | if (nextToken.equals("}")) { 57 | i++; 58 | buf.append("{ }"); 59 | } else { 60 | count++; 61 | buf.append(token); 62 | doFill(buf, count, fillStringUnit); 63 | } 64 | continue; 65 | } 66 | if (token.equals("}")) { 67 | count--; 68 | doFill(buf, count, fillStringUnit); 69 | buf.append(token); 70 | continue; 71 | } 72 | if (token.equals("[")) { 73 | String nextToken = tokenList.get(i + 1); 74 | if (nextToken.equals("]")) { 75 | i++; 76 | buf.append("[ ]"); 77 | } else { 78 | count++; 79 | buf.append(token); 80 | doFill(buf, count, fillStringUnit); 81 | } 82 | continue; 83 | } 84 | if (token.equals("]")) { 85 | count--; 86 | doFill(buf, count, fillStringUnit); 87 | buf.append(token); 88 | continue; 89 | } 90 | 91 | buf.append(token); 92 | //左对齐 93 | if (i < tokenList.size() - 1 && tokenList.get(i + 1).equals(":")) { 94 | int fillLength = fixedLenth - token.getBytes().length; 95 | if (fillLength > 0) { 96 | for(int j = 0; j < fillLength; j++) { 97 | buf.append(" "); 98 | } 99 | } 100 | } 101 | } 102 | return buf.toString(); 103 | } 104 | 105 | private static String getToken(String json) { 106 | StringBuilder buf = new StringBuilder(); 107 | boolean isInYinHao = false; 108 | while (json.length() > 0) { 109 | String token = json.substring(0, 1); 110 | json = json.substring(1); 111 | 112 | if (!isInYinHao && 113 | (token.equals(":") || token.equals("{") || token.equals("}") 114 | || token.equals("[") || token.equals("]") 115 | || token.equals(","))) { 116 | if (buf.toString().trim().length() == 0) { 117 | buf.append(token); 118 | } 119 | 120 | break; 121 | } 122 | 123 | if (token.equals("\\")) { 124 | buf.append(token); 125 | buf.append(json.substring(0, 1)); 126 | json = json.substring(1); 127 | continue; 128 | } 129 | if (token.equals("\"")) { 130 | buf.append(token); 131 | if (isInYinHao) { 132 | break; 133 | } else { 134 | isInYinHao = true; 135 | continue; 136 | } 137 | } 138 | buf.append(token); 139 | } 140 | return buf.toString(); 141 | } 142 | 143 | private static void doFill(StringBuilder buf, int count, String fillStringUnit) { 144 | buf.append("\n"); 145 | for (int i = 0; i < count; i++) { 146 | buf.append(fillStringUnit); 147 | } 148 | } 149 | 150 | } -------------------------------------------------------------------------------- /zb_api_rest_java/src/main/java/com/zb/kits/MapSort.java: -------------------------------------------------------------------------------- 1 | package com.zb.kits; 2 | 3 | import java.util.Comparator; 4 | import java.util.HashMap; 5 | import java.util.Iterator; 6 | import java.util.Map; 7 | import java.util.Map.Entry; 8 | import java.util.TreeMap; 9 | 10 | public class MapSort { 11 | 12 | public static void main(String[] args) { 13 | 14 | Map map = new HashMap(); 15 | 16 | map.put("Kb", "K"); 17 | map.put("Wc", "W"); 18 | map.put("Ab", "A"); 19 | map.put("ad", "a"); 20 | map.put("Fe", "N"); 21 | map.put("Bf", "B"); 22 | map.put("Cg", "C"); 23 | map.put("Zh", "Z"); 24 | 25 | Map resultMap = sortMapByKey(map); // 按Key进行排序,根据首字母hashcode 26 | 27 | for (Map.Entry entry : resultMap.entrySet()) { 28 | System.out.println(entry.getKey() + " " + entry.getValue()); 29 | } 30 | 31 | } 32 | 33 | /** 34 | * 使用 Map按key首字母hashcode进行排序 35 | * 36 | * @param map 37 | * @return 38 | */ 39 | public static Map sortMapByKey(Map map) { 40 | if (map == null || map.isEmpty()) { 41 | return null; 42 | } 43 | 44 | Map sortMap = new TreeMap(new MapKeyComparator()); 45 | 46 | sortMap.putAll(map); 47 | 48 | return sortMap; 49 | } 50 | 51 | public static String toStringMap(Map m) { 52 | // 按map键首字母顺序进行排序 53 | m = MapSort.sortMapByKey(m); 54 | 55 | StringBuilder sbl = new StringBuilder(); 56 | for (Iterator i = m.entrySet().iterator(); i.hasNext();) { 57 | Entry e = i.next(); 58 | Object o = e.getValue(); 59 | String v = ""; 60 | if (o == null) { 61 | v = ""; 62 | } else if (o instanceof String[]) { 63 | String[] s = (String[]) o; 64 | if (s.length > 0) { 65 | v = s[0]; 66 | } 67 | } else { 68 | v = o.toString(); 69 | } 70 | if (!e.getKey().equals("sign") && !e.getKey().equals("reqTime") && !e.getKey().equals("tx")) { 71 | // try { 72 | // sbl.append("&").append(e.getKey()).append("=").append(URLEncoder.encode(v, 73 | // "utf-8")); 74 | // } catch (UnsupportedEncodingException e1) { 75 | // e1.printStackTrace(); 76 | sbl.append("&").append(e.getKey()).append("=").append(v); 77 | // } 78 | } 79 | } 80 | String s = sbl.toString(); 81 | if (s.length() > 0) { 82 | return s.substring(1); 83 | } 84 | return ""; 85 | } 86 | } 87 | 88 | class MapKeyComparator implements Comparator { 89 | 90 | public int compare(String str1, String str2) { 91 | 92 | return str1.compareTo(str2); 93 | } 94 | } -------------------------------------------------------------------------------- /zb_api_rest_java/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | Archetype Created Web Application 8 | 9 | -------------------------------------------------------------------------------- /zb_api_rest_java/src/test/java/com/zb/api/RestTest.java: -------------------------------------------------------------------------------- 1 | package com.zb.api; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.io.InputStreamReader; 7 | import java.net.HttpURLConnection; 8 | import java.net.URL; 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | 12 | import org.apache.http.HttpException; 13 | import org.apache.log4j.Logger; 14 | import org.junit.Test; 15 | 16 | import com.alibaba.fastjson.JSONObject; 17 | import com.zb.kits.EncryDigestUtil; 18 | import com.zb.kits.HttpUtilManager; 19 | import com.zb.kits.MapSort; 20 | 21 | public class RestTest { 22 | 23 | private static Logger log = Logger.getLogger(RestTest.class); 24 | 25 | // 正式 26 | public final String ACCESS_KEY = ""; 27 | public final String SECRET_KEY = ""; 28 | public final String URL_PREFIX = "https://trade.zb.com/api/"; 29 | public static String API_DOMAIN = "http://api.zb.com"; 30 | 31 | 32 | public final String PAY_PASS = "xxxx"; 33 | 34 | /** 35 | * 委托下单 tradeType 1买,0卖 36 | */ 37 | @Test 38 | public void testOrder() { 39 | try { 40 | // 需加密的请求参数, tradeType=0卖单 41 | Map params = new HashMap(); 42 | params.put("method", "order"); 43 | params.put("price", "1.9001"); 44 | params.put("amount", "1.502"); 45 | params.put("tradeType", "1"); 46 | params.put("currency", "qtum_usdt"); 47 | 48 | // 请求测试 49 | String json = this.getJsonPost(params); 50 | System.out.println("testOrder 结果: " + json); 51 | } catch (Exception ex) { 52 | ex.printStackTrace(); 53 | } 54 | } 55 | 56 | /** 57 | * 取消下单 58 | */ 59 | // @Test 60 | public void testCancelOrder() { 61 | String orderId = "201710111625";// 201710111608 62 | try { 63 | Map params = new HashMap(); 64 | params.put("method", "cancelOrder"); 65 | params.put("id", orderId); 66 | params.put("currency", "ltc_btc"); 67 | 68 | String json = this.getJsonPost(params); 69 | System.out.println("testGetOrder 结果: " + json); 70 | } catch (Exception ex) { 71 | ex.printStackTrace(); 72 | } 73 | } 74 | 75 | /** 76 | * 获取订单信息 77 | */ 78 | // @Test 79 | public void testGetOrder() { 80 | String orderId = "201710122805"; 81 | try { 82 | Map params = new HashMap(); 83 | params.put("method", "getOrder"); 84 | params.put("id", orderId); 85 | params.put("currency", "ltc_btc"); 86 | String json = this.getJsonPost(params); 87 | 88 | System.out.println("testGetOrder 结果: " + json); 89 | } catch (Exception ex) { 90 | ex.printStackTrace(); 91 | } 92 | } 93 | 94 | /** 95 | * 获取多个委托买单或卖单,每次请求返回10条记录 96 | */ 97 | // @Test 98 | public void testGetOrders() { 99 | try { 100 | String[] currencyArr = new String[] { "ltc_btc", "eth_btc", "etc_btc" }; 101 | for (String currency : currencyArr) { 102 | Map params = new HashMap(); 103 | params.put("method", "getOrders"); 104 | params.put("tradeType", "1"); 105 | params.put("currency", currency); 106 | params.put("pageIndex", "1"); 107 | 108 | String json = this.getJsonPost(params); 109 | log.info("testGetOrders 结果: " + json); 110 | } 111 | } catch (Exception ex) { 112 | ex.printStackTrace(); 113 | } 114 | } 115 | 116 | /** 117 | * (新)获取多个委托买单或卖单,每次请求返回pageSize<=100条记录 118 | */ 119 | // @Test 120 | public void testGetOrdersNew() { 121 | try { 122 | String[] currencyArr = new String[] { "ltc_btc", "eth_btc", "etc_btc" }; 123 | for (String currency : currencyArr) { 124 | Map params = new HashMap(); 125 | params.put("method", "getOrdersNew"); 126 | params.put("tradeType", "1"); 127 | params.put("currency", currency); 128 | params.put("pageIndex", "1"); 129 | params.put("pageSize", "1"); 130 | String json = this.getJsonPost(params); 131 | log.info("testGetOrdersNew 结果: " + json); 132 | } 133 | } catch (Exception ex) { 134 | ex.printStackTrace(); 135 | } 136 | 137 | } 138 | 139 | /** 140 | * 与getOrdersNew的区别是取消tradeType字段过滤,可同时获取买单和卖单,每次请求返回pageSize<=100条记录 141 | */ 142 | // @Test 143 | public void getOrdersIgnoreTradeType() { 144 | try { 145 | String[] currencyArr = new String[] { "ltc_btc", "eth_btc", "etc_btc" }; 146 | for (String currency : currencyArr) { 147 | Map params = new HashMap(); 148 | params.put("method", "getOrdersIgnoreTradeType"); 149 | params.put("currency", currency); 150 | params.put("pageIndex", "1"); 151 | params.put("pageSize", "1"); 152 | 153 | String json = this.getJsonPost(params); 154 | log.info("getOrdersIgnoreTradeType 结果: " + json); 155 | } 156 | } catch (Exception ex) { 157 | ex.printStackTrace(); 158 | } 159 | 160 | } 161 | 162 | /** 163 | * 获取未成交或部份成交的买单和卖单,每次请求返回pageSize<=100条记录 164 | */ 165 | // @Test 166 | public void getUnfinishedOrdersIgnoreTradeType() { 167 | try { 168 | String[] currencyArr = new String[] { "ltc_btc", "eth_btc", "etc_btc" }; 169 | for (String currency : currencyArr) { 170 | Map params = new HashMap(); 171 | params.put("method", "getUnfinishedOrdersIgnoreTradeType"); 172 | params.put("currency", currency); 173 | params.put("pageIndex", "1"); 174 | params.put("pageSize", "10"); 175 | 176 | String json = this.getJsonPost(params); 177 | log.info("getUnfinishedOrdersIgnoreTradeType 结果: " + json); 178 | } 179 | } catch (Exception ex) { 180 | ex.printStackTrace(); 181 | } 182 | } 183 | 184 | /** 185 | * 获取个人信息 186 | */ 187 | @Test 188 | public void testGetAccountInfo() { 189 | try { 190 | // 需加密的请求参数 191 | Map params = new HashMap(); 192 | params.put("method", "getAccountInfo"); 193 | String json = this.getJsonPost(params); 194 | log.info("testGetAccountInfo 结果: " + json); 195 | } catch (Exception ex) { 196 | ex.printStackTrace(); 197 | } 198 | } 199 | 200 | /** 201 | * 获取个人的充值地址 202 | */ 203 | // @Test 204 | public void testGetUserAddress() { 205 | try { 206 | // 需加密的请求参数 207 | Map params = new HashMap(); 208 | params.put("method", "getUserAddress"); 209 | params.put("currency", "btc"); 210 | String json = this.getJsonPost(params); 211 | System.out.println("getUserAddress 结果: " + json); 212 | } catch (Exception ex) { 213 | ex.printStackTrace(); 214 | } 215 | } 216 | 217 | /** 218 | * 获取认证的提现地址 219 | */ 220 | // @Test 221 | public void testGetWithdrawAddress() { 222 | try { 223 | Map params = new HashMap(); 224 | params.put("method", "getWithdrawAddress"); 225 | params.put("currency", "etc"); 226 | 227 | String json = this.getJsonPost(params); 228 | System.out.println("getWithdrawAddress 结果: " + json); 229 | } catch (Exception ex) { 230 | ex.printStackTrace(); 231 | } 232 | } 233 | 234 | /** 235 | * 获取提现记录 236 | */ 237 | // @Test 238 | public void testGetWithdrawRecord() { 239 | try { 240 | Map params = new HashMap(); 241 | params.put("method", "getWithdrawRecord"); 242 | params.put("currency", "eth"); 243 | params.put("pageIndex", "1"); 244 | params.put("pageSize", "10"); 245 | String json = this.getJsonPost(params); 246 | System.out.println("getWithdrawRecord 结果: " + json); 247 | } catch (Exception ex) { 248 | ex.printStackTrace(); 249 | } 250 | } 251 | 252 | /** 253 | * 获取虚拟货币充值记录 254 | */ 255 | // @Test 256 | public void testGetChargeRecord() { 257 | try { 258 | Map params = new HashMap(); 259 | params.put("method", "getChargeRecord"); 260 | params.put("currency", "btc"); 261 | params.put("pageIndex", "1"); 262 | params.put("pageSize", "10"); 263 | String json = this.getJsonPost(params); 264 | 265 | System.out.println("getChargeRecord 结果: " + json); 266 | 267 | } catch (Exception ex) { 268 | ex.printStackTrace(); 269 | } 270 | } 271 | 272 | /** 273 | * 提现操作 274 | */ 275 | // @Test 276 | public void withdraw() { 277 | try { 278 | String addr = "143GwqgnjNi5DqGv4xzwqeGTi7BGxxxxxx"; 279 | String fees = "0.0003"; 280 | String currency = "etc"; 281 | String amount = "0.0004"; 282 | String itransfer = "0"; 283 | 284 | Map params = new HashMap(); 285 | params.put("amount", amount); 286 | params.put("currency", currency); 287 | params.put("fees", fees); 288 | params.put("itransfer", itransfer); 289 | params.put("method", "withdraw"); 290 | params.put("receiveAddr", addr); 291 | params.put("safePwd", PAY_PASS); 292 | 293 | String json= this.getJsonPost(params); 294 | System.out.println("withdraw 结果: " + json); 295 | } catch (Exception ex) { 296 | ex.printStackTrace(); 297 | } 298 | } 299 | 300 | 301 | 302 | 303 | /** 304 | * 测试获取行情 305 | */ 306 | // @Test 307 | public void testTicker() { 308 | try { 309 | String currency = "ltc_btc"; 310 | // 请求地址 311 | String url = API_DOMAIN + "/data/v1/ticker?market=" + currency; 312 | log.info(currency + "-testTicker url: " + url); 313 | // 请求测试 314 | String callback = get(url, "UTF-8"); 315 | log.info(currency + "-testTicker 结果: " + callback); 316 | } catch (Exception ex) { 317 | ex.printStackTrace(); 318 | } 319 | } 320 | 321 | /** 322 | * 测试获取深度 323 | */ 324 | // @Test 325 | public void testDepth() { 326 | try { 327 | String currency = "ltc_btc"; 328 | String merge = "0.1"; 329 | // 请求地址 330 | String url = API_DOMAIN + "/data/v1/depth?market=" + currency; 331 | // String url = API_DOMAIN+"/data/v1/depth?currency=" + currency + 332 | // "&size=3&merge=" + merge; 333 | // String url = API_DOMAIN+"/data/v1/depth?currency=" + currency + 334 | // "&size=3"; 335 | log.info(currency + "-testDepth url: " + url); 336 | // 请求测试 337 | String callback = get(url, "UTF-8"); 338 | log.info(currency + "-testDepth 结果: " + callback); 339 | } catch (Exception ex) { 340 | ex.printStackTrace(); 341 | } 342 | } 343 | 344 | /** 345 | * 测试获取最近交易记录 346 | */ 347 | // @Test 348 | public void testTrades() { 349 | try { 350 | String currency = "etc_btc"; 351 | // 请求地址 352 | String url = API_DOMAIN + "/data/v1/trades?market=" + currency; 353 | log.info(currency + "-testTrades url: " + url); 354 | // 请求测试 355 | String callback = get(url, "UTF-8"); 356 | log.info(currency + "-testTrades 结果: " + callback); 357 | } catch (Exception ex) { 358 | ex.printStackTrace(); 359 | } 360 | } 361 | 362 | /** 363 | * 测试获取K线数据 364 | */ 365 | // @Test 366 | public void testKline() { 367 | try { 368 | String currency = "etc_btc"; 369 | // 请求地址 370 | String url = API_DOMAIN + "/data/v1/kline?market=" + currency + "×=1min"; 371 | log.info(currency + "-testKline url: " + url); 372 | // 请求测试 373 | String callback = get(url, "UTF-8"); 374 | JSONObject json = JSONObject.parseObject(callback); 375 | log.info(currency + "-testKline 结果: " + json.toJSONString()); 376 | } catch (Exception ex) { 377 | ex.printStackTrace(); 378 | } 379 | } 380 | 381 | /** 382 | * 获取json内容(统一加密) 383 | * 384 | * @param params 385 | * @return 386 | */ 387 | private String getJsonPost(Map params) { 388 | params.put("accesskey", ACCESS_KEY);// 这个需要加入签名,放前面 389 | String digest = EncryDigestUtil.digest(SECRET_KEY); 390 | 391 | String sign = EncryDigestUtil.hmacSign(MapSort.toStringMap(params), digest); // 参数执行加密 392 | String method = params.get("method"); 393 | 394 | // 加入验证 395 | params.put("sign", sign); 396 | params.put("reqTime", System.currentTimeMillis() + ""); 397 | String url = "请求地址:" + URL_PREFIX + method + " 参数:" + params; 398 | System.out.println(url); 399 | String json = ""; 400 | try { 401 | json = HttpUtilManager.getInstance().requestHttpPost(URL_PREFIX, method, params); 402 | } catch (HttpException | IOException e) { 403 | log.error("获取交易json异常", e); 404 | } 405 | return json; 406 | } 407 | 408 | /** 409 | * 410 | * @param urlAll 411 | * :请求接口 412 | * @param charset 413 | * :字符编码 414 | * @return 返回json结果 415 | */ 416 | public String get(String urlAll, String charset) { 417 | BufferedReader reader = null; 418 | String result = null; 419 | StringBuffer sbf = new StringBuffer(); 420 | String userAgent = "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36";// 模拟浏览器 421 | try { 422 | URL url = new URL(urlAll); 423 | HttpURLConnection connection = (HttpURLConnection) url.openConnection(); 424 | connection.setRequestMethod("GET"); 425 | connection.setReadTimeout(30000); 426 | connection.setConnectTimeout(30000); 427 | connection.setRequestProperty("User-agent", userAgent); 428 | connection.connect(); 429 | InputStream is = connection.getInputStream(); 430 | reader = new BufferedReader(new InputStreamReader(is, charset)); 431 | String strRead = null; 432 | while ((strRead = reader.readLine()) != null) { 433 | sbf.append(strRead); 434 | sbf.append("\r\n"); 435 | } 436 | reader.close(); 437 | result = sbf.toString(); 438 | 439 | } catch (Exception e) { 440 | e.printStackTrace(); 441 | } 442 | return result; 443 | } 444 | } 445 | -------------------------------------------------------------------------------- /zb_api_rest_java/src/test/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | ##????? 2 | ## %r ?? 0 3 | ## %t ??? main 4 | ## %p ??? DEBUG/INFO/ERROR 5 | ## %c ??????(????) 6 | ## %l ????????????? 7 | ## %m ????????????log(message)??message 8 | ## %n ?????? 9 | 10 | 11 | 12 | #log4j????logger 13 | #FATAL 0 14 | #ERROR 3 15 | #WARN 4 16 | #INFO 6 17 | #DEBUG 7 18 | ### set log levels ### 19 | log4j.rootLogger = INFO,stdout,file,error 20 | ###???? 21 | log4j.appender.logfile.encoding=UTF-8 22 | ### ?????? ### 23 | log4j.appender.stdout = org.apache.log4j.ConsoleAppender 24 | log4j.appender.stdout.Target = System.out 25 | log4j.appender.stdout.layout = org.apache.log4j.PatternLayout 26 | log4j.appender.stdout.layout.ConversionPattern =[%5p]\:%d{MM-dd HH\:mm\:ss} %l- %m%n 27 | 28 | ### ??????? ### 29 | log4j.appender.file = org.apache.log4j.DailyRollingFileAppender 30 | log4j.appender.file.File = logs/chbtc_rest_demo_log 31 | log4j.appender.file.DatePattern = '_'yyyy-MM-dd'.log' 32 | log4j.appender.file.Append = true 33 | ## ??DEBUG??????? 34 | log4j.appender.file.Threshold = INFO 35 | log4j.appender.file.layout = org.apache.log4j.PatternLayout 36 | log4j.appender.file.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n 37 | 38 | ### ??????????? ### 39 | log4j.appender.error = org.apache.log4j.DailyRollingFileAppender 40 | ## ??????? 41 | log4j.appender.error.File = logs/chbtc_rest_demo_error 42 | log4j.appender.error.DatePattern = '_'yyyy-MM-dd'.log' 43 | log4j.appender.error.Append = true 44 | ## ???ERROR???????!!! 45 | log4j.appender.error.Threshold = ERROR 46 | log4j.appender.error.layout = org.apache.log4j.PatternLayout 47 | log4j.appender.error.layout.ConversionPattern =%d{yyyy-MM-dd HH\:mm\:ss} [ %t\:%r ] - [ %p ] %m%n -------------------------------------------------------------------------------- /zb_netty_client_java/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | com.world 4 | netty_client_demo 5 | 0.0.1-SNAPSHOT 6 | netty_client_demo 7 | http://maven.apache.org 8 | 9 | 10 | junit 11 | junit 12 | 3.8.1 13 | test 14 | 15 | 16 | com.alibaba 17 | fastjson 18 | 1.1.41 19 | 20 | 21 | log4j 22 | log4j 23 | 1.2.16 24 | 25 | 26 | io.netty 27 | netty-all 28 | 4.0.28.Final 29 | 30 | 31 | 32 | 33 | netty_client_demo 34 | src/main/java 35 | 36 | 37 | org.apache.maven.plugins 38 | maven-compiler-plugin 39 | 2.3.2 40 | 41 | 1.7 42 | 1.7 43 | UTF-8 44 | 45 | 46 | 47 | org.apache.maven.plugins 48 | maven-jar-plugin 49 | 50 | 51 | 52 | true 53 | lib/ 54 | websocketx.client.WebSocketClient 55 | 56 | 57 | 61 | 62 | 63 | 64 | org.apache.maven.plugins 65 | maven-dependency-plugin 66 | 67 | 68 | copy 69 | package 70 | 71 | copy-dependencies 72 | 73 | 74 | ${project.build.directory}/lib 75 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /zb_netty_client_java/src/main/java/com/world/common/SysEnum.java: -------------------------------------------------------------------------------- 1 | package com.world.common; 2 | 3 | public interface SysEnum { 4 | public int getKey(); 5 | public String getValue(); 6 | } 7 | -------------------------------------------------------------------------------- /zb_netty_client_java/src/main/java/com/world/common/SystemCode.java: -------------------------------------------------------------------------------- 1 | package com.world.common; 2 | 3 | public enum SystemCode implements SysEnum{ 4 | 5 | code_1000(1000, "操作成功", "success"), 6 | code_1001(1001, "一般错误提示", "error tips"), 7 | 8 | code_1002(1002, "内部错误", "Internal Error"), 9 | code_1003(1003, "验证不通过", "Validate No Pass"), 10 | code_1004(1004, "安全密码锁定", "Safe Password Locked"), 11 | code_1005(1005, "安全密码错误", "Safe Password Error"), 12 | code_1006(1006, "实名认证等待审核或审核不通过", "Audit Or Audit No Pass"), 13 | 14 | code_2001(2001 , "人民币账户余额不足" , "Insufficient CNY Balance"), 15 | code_2002(2002 , "比特币账户余额不足" , "Insufficient BTC Balance"), 16 | code_2003(2003 , "莱特币账户余额不足" , "Insufficient LTC Balance"), 17 | code_2004(2004 , "比特权账户余额不足" , "Insufficient BTQ Balance"), 18 | 19 | code_3001(3001 , "挂单没有找到" , "Not Found Order"), 20 | code_3002(3002 , "无效的金额" , "Invalid Money"), 21 | code_3003(3003 , "无效的数量" , "Invalid Amount"), 22 | code_3004(3004 , "用户不存在" , "No Such User"), 23 | code_3005(3005 , "无效的参数" , "Invalid Arguments"), 24 | code_3006(3006 , "无效的IP或与绑定的IP不一致", "Invalid Ip Address"), 25 | code_3007(3007 , "请求时间已失效", "Invalid Ip Request Time"), 26 | 27 | code_4001(4001 , "API接口被锁定或未启用", "API Locked Or Not Enabled"), 28 | code_4002(4002 , "请求过于频繁", "Request Too Frequently"); 29 | 30 | private SystemCode(int key, String value , String className) { 31 | this.key = key; 32 | this.value = value; 33 | this.className = className; 34 | } 35 | 36 | private int key; 37 | private String value; 38 | private String className; 39 | 40 | public int getKey() { 41 | return key; 42 | } 43 | 44 | public String getValue() { 45 | return value; 46 | } 47 | public String getClassName() { 48 | return className; 49 | } 50 | 51 | public void setClassName(String className){ 52 | this.className = className; 53 | } 54 | 55 | public void setValue(String value){ 56 | this.value = value; 57 | } 58 | 59 | public static SystemCode getCode(int key){ 60 | SystemCode code = null; 61 | for (SystemCode s : SystemCode.values()){ 62 | if(s.getKey() == key){ 63 | code = s; 64 | break; 65 | } 66 | } 67 | return code; 68 | } 69 | 70 | public static SystemCode getSystemCode(int key){ 71 | switch(key){ 72 | case 2: { 73 | return SystemCode.code_1002; 74 | } 75 | case 100: { 76 | return SystemCode.code_1000; 77 | } 78 | case 130: { 79 | SystemCode code = SystemCode.code_1001; 80 | code.setClassName("委托失败-未知的委托类型"); 81 | code.setValue("委托失败-未知的委托类型"); 82 | return code; 83 | } 84 | case 131: { 85 | return SystemCode.code_3005; 86 | } 87 | case 132: { 88 | SystemCode code = SystemCode.code_1001; 89 | code.setClassName("委托失败-还有卖比特币委托已经达到您本次购买的报价"); 90 | code.setValue("委托失败-还有卖比特币委托已经达到您本次购买的报价"); 91 | return code; 92 | } 93 | case 133: { 94 | SystemCode code = SystemCode.code_1001; 95 | code.setClassName("委托失败-还有买比特币委托已经达到您本次卖出的报价"); 96 | code.setValue("委托失败-还有买比特币委托已经达到您本次卖出的报价"); 97 | return code; 98 | } 99 | case 135: { 100 | return SystemCode.code_2001; 101 | } 102 | case 136: { 103 | return SystemCode.code_1002; 104 | } 105 | case 137: { 106 | SystemCode code = SystemCode.code_1001; 107 | code.setClassName("委托失败-价格太高、暂不支持"); 108 | code.setValue("委托失败-价格太高、暂不支持"); 109 | return code; 110 | } 111 | case 200: { 112 | return SystemCode.code_1000; 113 | } 114 | case 211: { 115 | return SystemCode.code_3001; 116 | } 117 | case 212: { 118 | SystemCode code = SystemCode.code_1001; 119 | code.setClassName("委托取消单个失败-已经提交过取消请求"); 120 | code.setValue("委托取消单个失败-已经提交过取消请求"); 121 | return code; 122 | } 123 | case 213: { 124 | SystemCode code = SystemCode.code_1001; 125 | code.setClassName("委托取消单个失败-取消程序"); 126 | code.setValue("委托取消单个失败-取消程序"); 127 | return code; 128 | } 129 | case 221: { 130 | return SystemCode.code_3001; 131 | } 132 | case 222: { 133 | SystemCode code = SystemCode.code_1001; 134 | code.setClassName("委托取消区间订单失败-区间价格可能颠倒导致错误"); 135 | code.setValue("委托取消区间订单失败-事物处理失败"); 136 | return code; 137 | } 138 | case 300: { 139 | return SystemCode.code_1000; 140 | } 141 | case 301: { 142 | return SystemCode.code_1000; 143 | } 144 | case 311: { 145 | SystemCode code = SystemCode.code_1001; 146 | code.setClassName("委托失败-未知的委托类型"); 147 | code.setValue("委托失败-未知的委托类型"); 148 | return code; 149 | } 150 | case 312: { 151 | SystemCode code = SystemCode.code_1001; 152 | code.setClassName("委托失败-事物处理失败"); 153 | code.setValue("委托失败-事物处理失败"); 154 | return code; 155 | } 156 | case 400: { 157 | return SystemCode.code_1000; 158 | } 159 | case 411: { 160 | return SystemCode.code_3001; 161 | } 162 | case 412: { 163 | SystemCode code = SystemCode.code_1001; 164 | code.setClassName("处理取消委托失败-已经成功委托"); 165 | code.setValue("处理取消委托失败-已经成功委托"); 166 | return code; 167 | } 168 | case 413: { 169 | SystemCode code = SystemCode.code_1001; 170 | code.setClassName("处理取消委托失败-事物处理失败"); 171 | code.setValue("处理取消委托失败-事物处理失败"); 172 | return code; 173 | } 174 | } 175 | return null; 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /zb_netty_client_java/src/main/java/com/world/common/VerifiUtil.java: -------------------------------------------------------------------------------- 1 | package com.world.common; 2 | // 3 | //import java.util.HashMap; 4 | //import java.util.Map; 5 | // 6 | //import javax.servlet.http.HttpServletRequest; 7 | // 8 | //import net.sf.json.JSONObject; 9 | // 10 | //import org.apache.commons.lang.StringUtils; 11 | // 12 | //import com.chbtc.api.ChbtcResponse; 13 | //import com.chbtc.api.user.UserManager; 14 | //import com.world.cache.Cache; 15 | //import com.world.controller.Base; 16 | //import com.world.controller.api.Index; 17 | //import com.world.util.ip.IpUtil; 18 | //import com.world.util.sign.EncryDigestUtil; 19 | // 20 | ///** 21 | // * API接口验证工具 22 | // * @author guosj 23 | // */ 24 | public class VerifiUtil { 25 | // 26 | // private Map map; 27 | // //API方法固定的参数 28 | // private String[] order = {"method", "accesskey", "price", "amount", "tradeType", "currency"}; 29 | // private String[] cancelOrder = {"method", "accesskey", "id", "currency"}; 30 | // private String[] getOrder = {"method", "accesskey", "id", "currency"}; 31 | // private String[] getOrders = {"method", "accesskey", "tradeType", "currency", "pageIndex"}; 32 | // private String[] getOrdersNew = {"method", "accesskey", "tradeType", "currency", "pageIndex", "pageSize"}; 33 | // private String[] getOrdersIgnoreTradeType = {"method", "accesskey", "currency", "pageIndex", "pageSize"}; 34 | // private String[] getUnfinishedOrdersIgnoreTradeType = {"method", "accesskey", "currency", "pageIndex", "pageSize"}; 35 | // private String[] getAccountInfo = {"method", "accesskey"}; 36 | // 37 | // private static VerifiUtil verifiUtil; 38 | // 39 | // public static Map users; 40 | // 41 | // // 42 | // public static VerifiUtil getInstance(){ 43 | // if(verifiUtil != null) 44 | // return verifiUtil; 45 | // else 46 | // return new VerifiUtil(); 47 | // } 48 | // 49 | // public VerifiUtil(){ 50 | // map = new HashMap(); 51 | // map.put("order", order); 52 | // map.put("cancelOrder", cancelOrder); 53 | // map.put("getOrder", getOrder); 54 | // map.put("getOrders", getOrders); 55 | // map.put("getOrdersNew", getOrdersNew); 56 | // map.put("getOrdersIgnoreTradeType", getOrdersIgnoreTradeType); 57 | // map.put("getUnfinishedOrdersIgnoreTradeType", getUnfinishedOrdersIgnoreTradeType); 58 | // map.put("getAccountInfo", getAccountInfo); 59 | // } 60 | // 61 | // /** 62 | // * 获取指定按顺序的参数 63 | // * @return 64 | // */ 65 | // public String[] getFixedArguments(String method){ 66 | // return (String[]) map.get(method); 67 | // } 68 | // 69 | // /** 70 | // * API访问请求验证 71 | // * @param info 72 | // * @param key 73 | // * @param secret 74 | // * @return 75 | // */ 76 | // public Object validateAuthAccess(Index index, HttpServletRequest request){ 77 | // boolean flag = false; 78 | // try{ 79 | // String key = request.getParameter("accesskey"); //用户传递访问key 80 | // long reqTime = new Long(request.getParameter("reqTime")); //用记的请求时间 81 | // String authInfo = request.getParameter("sign"); //用户根据URL生成的加密串 82 | // 83 | // //强制参数存在为空,不通过 84 | // if(StringUtils.isEmpty(authInfo) || StringUtils.isEmpty(key) || StringUtils.isEmpty(String.valueOf(reqTime))){ 85 | // return SystemCode.code_3005; 86 | // } 87 | // 88 | // //==============================Memory Cache 进行IP、访问限制验证=================================================== 89 | // //用户IP过滤 90 | // boolean ipLimit = true; 91 | // if(!ipLimit){ 92 | // SystemCode code = SystemCode.code_1001; 93 | // code.setClassName("当前IP请求过于频繁,已列入黑名单,API交易接口已自动关闭"); 94 | // code.setValue("当前IP请求过于频繁,已列入黑名单,API交易接口已自动关闭"); 95 | // //关闭API交易接口 96 | // ChbtcResponse response = UserManager.getInstance().closeUserAutoApi(key); 97 | // JSONObject json = JSONObject.fromObject(response.getMsg()); 98 | // if(response.taskIsFinish()){ 99 | // if(json.getBoolean("isSuc")){ 100 | // return code; 101 | // }else{ 102 | // return false; 103 | // } 104 | // }else{ 105 | // return false; 106 | // } 107 | // } 108 | // 109 | // //用户访问时间跟次数限制(相当必要) 110 | // Object accessLimit = accessLimit(request, key); 111 | // if(accessLimit instanceof SystemCode){ 112 | // return accessLimit; 113 | // }else{ 114 | // if(!((Boolean)accessLimit)) 115 | // return SystemCode.code_4002; 116 | // } 117 | // //================================================================================================================================================ 118 | // 119 | // if(users == null) users = new HashMap(); 120 | // 121 | // JSONObject userObject = (JSONObject) users.get("user_object_json_" + key); 122 | // //是否需要重新查询用户 123 | // if(userObject == null){ 124 | // ChbtcResponse response = UserManager.getInstance().getUserByAccessKey(key, 0); 125 | // if(response == null || !response.getMsg().startsWith("{")){ 126 | // return SystemCode.code_1003; 127 | // } 128 | // if(response.taskIsFinish()){ 129 | // JSONObject json = JSONObject.fromObject(response.getMsg()); 130 | // if(json.getBoolean("isSuc")){ 131 | // userObject = JSONObject.fromObject(json.getString("datas")); 132 | // //最后一次查询时间 133 | // users.put("user_object_json_" + key, userObject); 134 | // } 135 | // } 136 | // } 137 | // 138 | // if(userObject == null){ 139 | // return SystemCode.code_1003; 140 | // } 141 | // //System.out.println("----------用户当前状态------------" + userObject.getInt("apiStatus")); 142 | // //设置已经查询到的用户对象 143 | // index.setJsonObject(userObject); 144 | // 145 | // if(userObject.getInt("apiStatus") == 2){//API接口开放交易 146 | //// String apiIpBind = userObject.getString("apiIpBind"); 147 | //// //交易IP绑定 148 | //// if(StringUtils.isNotEmpty(apiIpBind)){ 149 | //// //如果申请了绑定交易IP则验证IP审核状态 150 | //// if(userObject.getInt("apiIpStatus") == 2){ 151 | //// //如果请求的IP与绑定的IP不一致 152 | //// if(!apiIpBind.equals(IpUtil.getIp(request))){//IP不一致 153 | //// return SystemCode.code_3006; 154 | //// } 155 | //// }else{ 156 | //// return SystemCode.code_4001; 157 | //// } 158 | //// } 159 | // 160 | // //服务器当前时间 161 | // long currTime = System.currentTimeMillis(); 162 | // //用户请求时间在必须在服务器时间前后5分钟 163 | // if(reqTime >= (currTime - 5*60*1000) && reqTime <= (currTime + 5*60*1000)){ 164 | // //获取用户加密的原信息 165 | // Object info = getAuthorization(request); 166 | // if(info instanceof SystemCode){ 167 | // return info; 168 | // }else{ 169 | // //与用户执行相同的加密方法,传入相同的secret 170 | // info = EncryDigestUtil.hmacSign((String)info, userObject.getString("apiSecret")); 171 | // //与用户的加密信息作比较 172 | // if(authInfo.equals(info)){ 173 | // flag = true; 174 | //// //验证通过,记录本次请求时间 175 | //// Data.Update("update btcuser set apiAuthTime=? where userId=?", new Object[]{reqTime, userObject.getString("userId")}); 176 | // } 177 | // } 178 | // } 179 | // }else{ 180 | // //Cache.Set("user_"+key+"_api_locked", String.valueOf("locked"), 30*60); 181 | // return SystemCode.code_4001; 182 | // } 183 | // }catch(Exception ex){ 184 | // ex.printStackTrace(); 185 | // return SystemCode.code_1002; 186 | // } 187 | // return flag; 188 | // } 189 | // 190 | // /** 191 | // * 用户加密原信息 192 | // * @param request 193 | // * @return 194 | // */ 195 | // private Object getAuthorization(HttpServletRequest request){ 196 | // String method = request.getRequestURI().substring(request.getRequestURI().lastIndexOf("/") + 1); 197 | // String[] fixedArguments = getFixedArguments(method); 198 | // StringBuffer buffer = new StringBuffer(); 199 | // int i = 0; 200 | // String value = ""; 201 | // for (String string : fixedArguments) { 202 | // if(i != 0){ 203 | // buffer.append("&"); 204 | // } 205 | // value = request.getParameter(string); 206 | // if(StringUtils.isEmpty(value)){ 207 | // return SystemCode.code_3005; 208 | // } 209 | // buffer.append(string).append("=").append(value); 210 | // i++; 211 | // } 212 | // return buffer.toString(); 213 | // } 214 | // 215 | // /** 216 | // * 访问限制 217 | // * 请求同一个方法,1s内只能请求一次 218 | // * 请求不同的方法,1s可以请求多次 219 | // * 请求同一个方法,1m内超过规定次数,视为恶意攻击,自动关闭API交易接口 220 | // * @param request 221 | // * @return 222 | // */ 223 | // public Object accessLimit(HttpServletRequest request, String key) throws Exception{ 224 | // //请求method 225 | // String method = request.getRequestURI().substring(request.getRequestURI().lastIndexOf("/") + 1); 226 | // //上一次的请求时间 227 | // String oldReqTime = Cache.Get(method + "_"+key); 228 | // //服务器当前时间 229 | // long currTime = System.currentTimeMillis(); 230 | // //缓存时间周期 231 | // int cycle = 30*60; 232 | // //一分钟内限制次数 233 | // int limitTimes = 1000; 234 | // //限制时间1分钟 235 | // int limitTime = 60 * 1000; 236 | // //一秒钟内限制次数 237 | // int slimitTimes = 20; 238 | // //还未请求过,或缓存已失效 239 | // if(StringUtils.isEmpty(oldReqTime)){ 240 | // Cache.Set(method+"_"+key, String.valueOf(currTime), cycle); 241 | // Cache.Set(method+"_"+key+"_one_min_times", "1", cycle); 242 | // Cache.Set(method+"_"+key+"_one_sec_times", "1", cycle); 243 | // Cache.Set(method+"_"+key+"_one_min_startTime", String.valueOf(currTime), cycle); 244 | // //Cache.Set("user_"+key+"_api_locked", String.valueOf("unlocked"), cycle); 245 | // return true; 246 | // }else{ 247 | // //判断该用户是否被锁住API了 248 | //// if("locked".equals(Cache.Get("user_"+key+"_api_locked"))){ 249 | //// return SystemCode.code_4001; 250 | //// } 251 | // 252 | // //上一次的请求时间 253 | // long old = new Long(oldReqTime); 254 | // //--------------------------------------限制一分钟内请求次数------------------------------------ 255 | // //请求次数 256 | // String times = Cache.Get(method+"_"+key+"_one_min_times"); 257 | // //根据用户建议,method=order其实需要分开为2个方法BTC/LTC 258 | // if(method.equalsIgnoreCase("order")){ 259 | // //限制次数增加300次 260 | // limitTimes += 300; 261 | // } 262 | // //第一次请求开始时间 263 | // String startTime = Cache.Get(method+"_"+key+"_one_min_startTime"); 264 | // 265 | // if(StringUtils.isEmpty(startTime)){ 266 | // //重新设置请求次数 267 | // Cache.Set(method+"_"+key+"_one_min_times", "1", cycle); 268 | // return true; 269 | // } 270 | // 271 | // //1分钟内请求超过limitTimes次,关闭该用户API交易接口,并清空缓存 272 | // if(Integer.parseInt(times) > limitTimes && currTime - new Long(startTime) < limitTime){ 273 | // Cache.Delete(method+"_"+key); 274 | // Cache.Delete(method+"_"+key+"_one_min_times"); 275 | // Cache.Delete(method+"_"+key+"_one_sec_times"); 276 | // Cache.Delete(method+"_"+key+"_one_min_startTime"); 277 | // //Cache.Set("user_"+key+"_api_locked", String.valueOf("locked"), cycle); 278 | // //关闭API交易接口 279 | // ChbtcResponse response = UserManager.getInstance().closeUserAutoApi(key); 280 | // JSONObject json = JSONObject.fromObject(response.getMsg()); 281 | // if(response.taskIsFinish()){ 282 | // if(json.getBoolean("isSuc")){ 283 | // return SystemCode.code_4001; 284 | // } 285 | // } 286 | // }else{ 287 | // int t = 0; 288 | // //如果缓存时间与当前请求时间超过1分钟,则更新缓存的开始时间,请求次数归0 289 | // if(currTime - new Long(startTime) >= limitTime){ 290 | // Cache.Set(method+"_"+key+"_one_min_startTime", String.valueOf(currTime), cycle); 291 | // t = 1; 292 | // }else{ 293 | // //如果请求次数到达limitTimes次,则重新数数 294 | // if(Integer.parseInt(times) == (limitTimes + 1)){ 295 | // t = 1; 296 | // }else{ 297 | // t = Integer.parseInt(times) + 1; 298 | // } 299 | // } 300 | // //重新设置请求次数 301 | // Cache.Set(method+"_"+key+"_one_min_times", String.valueOf(t), cycle); 302 | // } 303 | // //=========================================================================================== 304 | // //如果当前求比上一次请求时间>=1s 305 | // if(currTime - old >= 1000){ 306 | // Cache.Set(method + "_"+key, String.valueOf(currTime), cycle); 307 | // Cache.Set(method + "_"+key+"_one_sec_times", "1", cycle); 308 | // return true; 309 | // }else{ 310 | // //1秒钟内请求次数 311 | // int ost = Integer.parseInt(Cache.Get(method + "_"+key+"_one_sec_times")); 312 | // if(ost > slimitTimes){ 313 | // //请求过于频繁 314 | // return SystemCode.code_4002; 315 | // }else{ 316 | // Cache.Set(method + "_"+key, String.valueOf(currTime), cycle); 317 | // Cache.Set(method + "_"+key+"_one_sec_times", String.valueOf(ost+1), cycle); 318 | // return true; 319 | // } 320 | // } 321 | // } 322 | // } 323 | } 324 | -------------------------------------------------------------------------------- /zb_netty_client_java/src/main/java/com/world/model/entitys/Balance.java: -------------------------------------------------------------------------------- 1 | package com.world.model.entitys; 2 | 3 | /** 4 | * 可用资金、货币 5 | * @author guosj 6 | */ 7 | public class Balance { 8 | //货币标识 9 | private String currency; 10 | //货币符号 11 | private String symbol; 12 | //货币总量 13 | private double amount; 14 | 15 | public String getCurrency() { 16 | return currency; 17 | } 18 | public void setCurrency(String currency) { 19 | this.currency = currency; 20 | } 21 | public String getSymbol() { 22 | return symbol; 23 | } 24 | public void setSymbol(String symbol) { 25 | this.symbol = symbol; 26 | } 27 | public double getAmount() { 28 | return amount; 29 | } 30 | public void setAmount(double amount) { 31 | this.amount = amount; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /zb_netty_client_java/src/main/java/com/world/model/entitys/Base.java: -------------------------------------------------------------------------------- 1 | package com.world.model.entitys; 2 | 3 | /** 4 | * 基础信息 5 | * @author guosj 6 | */ 7 | public class Base { 8 | //用户名 9 | private String username; 10 | //是否开启安全密码 11 | private boolean trade_password_enabled; 12 | //是否启用手机认证 13 | private boolean auth_mobile_enabled; 14 | //是否启用谷歌认证 15 | private boolean auth_google_enabled; 16 | //private double trade_fee; 17 | 18 | 19 | 20 | public String getUsername() { 21 | return username; 22 | } 23 | public void setUsername(String username) { 24 | this.username = username; 25 | } 26 | public boolean isTrade_password_enabled() { 27 | return trade_password_enabled; 28 | } 29 | public void setTrade_password_enabled(boolean tradePasswordEnabled) { 30 | trade_password_enabled = tradePasswordEnabled; 31 | } 32 | public boolean isAuth_mobile_enabled() { 33 | return auth_mobile_enabled; 34 | } 35 | public void setAuth_mobile_enabled(boolean authMobileEnabled) { 36 | auth_mobile_enabled = authMobileEnabled; 37 | } 38 | public boolean isAuth_google_enabled() { 39 | return auth_google_enabled; 40 | } 41 | public void setAuth_google_enabled(boolean authGoogleEnabled) { 42 | auth_google_enabled = authGoogleEnabled; 43 | } 44 | // public double getTrade_fee() { 45 | // return trade_fee; 46 | // } 47 | // public void setTrade_fee(double tradeFee) { 48 | // trade_fee = tradeFee; 49 | // } 50 | // 51 | 52 | } 53 | -------------------------------------------------------------------------------- /zb_netty_client_java/src/main/java/com/world/model/entitys/Frozen.java: -------------------------------------------------------------------------------- 1 | package com.world.model.entitys; 2 | 3 | /** 4 | * 冻结资金、货币 5 | * @author guosj 6 | */ 7 | public class Frozen { 8 | //货币标识 9 | private String currency; 10 | //货币符号 11 | private String symbol; 12 | //货币总量 13 | private double amount; 14 | public String getCurrency() { 15 | return currency; 16 | } 17 | public void setCurrency(String currency) { 18 | this.currency = currency; 19 | } 20 | public String getSymbol() { 21 | return symbol; 22 | } 23 | public void setSymbol(String symbol) { 24 | this.symbol = symbol; 25 | } 26 | public double getAmount() { 27 | return amount; 28 | } 29 | public void setAmount(double amount) { 30 | this.amount = amount; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /zb_netty_client_java/src/main/java/com/world/model/entitys/Order.java: -------------------------------------------------------------------------------- 1 | package com.world.model.entitys; 2 | 3 | /** 4 | * 委托订单 5 | * @author guosj 6 | */ 7 | public class Order { 8 | 9 | //挂单ID 10 | private String id; 11 | //挂单类型 1/0 buy/sell 12 | private int type; 13 | //单价 14 | private double price; 15 | //挂单货币类型 btc/ltc 16 | private String currency; 17 | //已成交数量 18 | private double trade_amount; 19 | //已成交总金额 20 | private double trade_money; 21 | //挂单总数量 22 | private double total_amount; 23 | //挂单交易日期 24 | private long trade_date; 25 | //挂单状态 26 | private int status; 27 | 28 | public String getId() { 29 | return id; 30 | } 31 | public void setId(String id) { 32 | this.id = id; 33 | } 34 | public int getType() { 35 | return type; 36 | } 37 | public void setType(int type) { 38 | this.type = type; 39 | } 40 | public double getPrice() { 41 | return price; 42 | } 43 | public void setPrice(double price) { 44 | this.price = price; 45 | } 46 | public String getCurrency() { 47 | return currency; 48 | } 49 | public void setCurrency(String currency) { 50 | this.currency = currency; 51 | } 52 | 53 | public double getTrade_amount() { 54 | return trade_amount; 55 | } 56 | public void setTrade_amount(double tradeAmount) { 57 | trade_amount = tradeAmount; 58 | } 59 | public double getTotal_amount() { 60 | return total_amount; 61 | } 62 | public void setTotal_amount(double totalAmount) { 63 | total_amount = totalAmount; 64 | } 65 | public long getTrade_date() { 66 | return trade_date; 67 | } 68 | public void setTrade_date(long tradeDate) { 69 | trade_date = tradeDate; 70 | } 71 | public int getStatus() { 72 | return status; 73 | } 74 | public void setStatus(int status) { 75 | this.status = status; 76 | } 77 | public double getTrade_money() { 78 | return trade_money; 79 | } 80 | public void setTrade_money(double trade_money) { 81 | this.trade_money = trade_money; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /zb_netty_client_java/src/main/java/com/world/model/market/Arith.java: -------------------------------------------------------------------------------- 1 | package com.world.model.market; 2 | import java.math.BigDecimal; 3 | /** 4 | * 由于Java的简单类型不能够精确的对浮点数进行运算,这个工具类提供精 5 | * 确的浮点数运算,包括加减乘除和四舍五入。 6 | */ 7 | public class Arith { 8 | //默认除法运算精度 9 | private static final int DEF_DIV_SCALE = 10; 10 | //这个类不能实例化 11 | private Arith(){ 12 | } 13 | 14 | /** 15 | * 提供精确的加法运算。 16 | * @param v1 被加数 17 | * @param v2 加数 18 | * @return 两个参数的和 19 | */ 20 | public static double add(double v1,double v2){ 21 | BigDecimal b1 = new BigDecimal(Double.toString(v1)); 22 | BigDecimal b2 = new BigDecimal(Double.toString(v2)); 23 | return b1.add(b2).doubleValue(); 24 | } 25 | /** 26 | * 提供精确的减法运算。 27 | * @param v1 被减数 28 | * @param v2 减数 29 | * @return 两个参数的差 30 | */ 31 | public static double sub(double v1,double v2){ 32 | BigDecimal b1 = new BigDecimal(Double.toString(v1)); 33 | BigDecimal b2 = new BigDecimal(Double.toString(v2)); 34 | return b1.subtract(b2).doubleValue(); 35 | } 36 | /** 37 | * 提供精确的乘法运算。 38 | * @param v1 被乘数 39 | * @param v2 乘数 40 | * @return 两个参数的积 41 | */ 42 | public static double mul(double v1,double v2){ 43 | BigDecimal b1 = new BigDecimal(Double.toString(v1)); 44 | BigDecimal b2 = new BigDecimal(Double.toString(v2)); 45 | return b1.multiply(b2).doubleValue(); 46 | } 47 | 48 | /** 49 | * 提供精确的乘法运算。 50 | * @param v1 被乘数 51 | * @param v2 乘数 52 | * @return 两个参数的积 53 | */ 54 | public static long mul(double v1,long v2,int dian){ 55 | v1=round(v1,dian);//进行一个小数位的取舍,这样避免跑到外面 56 | BigDecimal b1 = new BigDecimal(Double.toString(v1)); 57 | BigDecimal b2 = new BigDecimal(Long.toString(v2)); 58 | return b1.multiply(b2).longValue(); 59 | } 60 | /** 61 | * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到 62 | * 小数点以后10位,以后的数字四舍五入。 63 | * @param v1 被除数 64 | * @param v2 除数 65 | * @return 两个参数的商 66 | */ 67 | public static double div(double v1,double v2){ 68 | return div(v1,v2,DEF_DIV_SCALE); 69 | } 70 | 71 | /** 72 | * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指 73 | * 定精度,以后的数字四舍五入。 74 | * @param v1 被除数 75 | * @param v2 除数 76 | * @param scale 表示表示需要精确到小数点以后几位。 77 | * @return 两个参数的商 78 | */ 79 | public static double div(double v1,double v2,int scale){ 80 | if(scale<0){ 81 | throw new IllegalArgumentException( 82 | "The scale must be a positive integer or zero"); 83 | } 84 | BigDecimal b1 = new BigDecimal(Double.toString(v1)); 85 | BigDecimal b2 = new BigDecimal(Double.toString(v2)); 86 | return b1.divide(b2,scale,BigDecimal.ROUND_DOWN).doubleValue(); 87 | 88 | } 89 | 90 | /** 91 | * 提供精确的小数位四舍五入处理。 92 | * @param v 需要四舍五入的数字 93 | * @param scale 小数点后保留几位 94 | * @return 四舍五入后的结果 95 | */ 96 | public static double round(double v,int scale){ 97 | if(scale<0){ 98 | throw new IllegalArgumentException( 99 | "The scale must be a positive integer or zero"); 100 | } 101 | BigDecimal b = new BigDecimal(Double.toString(v)); 102 | BigDecimal one = new BigDecimal("1"); 103 | return b.divide(one,scale,BigDecimal.ROUND_DOWN).doubleValue(); 104 | } 105 | public static void main(String args[]){ 106 | // System.out.println(add(0.05,0.01)); 107 | // System.out.println(1.0-0.42); 108 | // System.out.println(4.015*100); 109 | // System.out.println(123.3/100); 110 | // System.out.println(div(10,3)); 111 | // System.out.println(10/3); 112 | System.out.println(mul(23.89943,10000000,2)); 113 | 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /zb_netty_client_java/src/main/java/com/world/model/market/Market.java: -------------------------------------------------------------------------------- 1 | package com.world.model.market; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import java.util.ResourceBundle; 6 | 7 | public class Market { 8 | 9 | public String numberBi; 10 | public String numberBiEn; 11 | public String numberBiNote; 12 | public long numberBixNormal; 13 | public long numberBixShow;//"+//显示的计量单位是最小存储单位的倍数,不相等的时候会缩小到指定单位(等于小数点位数) 14 | public int numberBixDian;//=3;"+//小数点后几位,如果有小数的话 15 | public String exchangeBi;//=\"比特币\";"+ 16 | public String exchangeBiEn;//=\"BTC\";"+ 17 | public String exchangeBiNote;//=\"฿\";"+ 18 | public String market;//=\"btqdefault\";"+ 19 | public long exchangeBixNormal;//=100000000;"+//标准单位是最小存储单位的位数 20 | public long exchangeBixShow;//=100000000;"+//显示的计量单位是最小存储单位的倍数 21 | public int exchangeBixDian;//=4;"+//小数点后几位,如果有小数的话 22 | public String entrustUrlBase;//=\"/\";"+ 23 | 24 | public int maxPrice;//最大的档位 25 | 26 | public int webId; 27 | public String ip; 28 | public int port; 29 | public String hashSec;//加密公钥 30 | 31 | /** 32 | * 是否是简化版 33 | * @param isSimple 34 | * @return 35 | */ 36 | public String toString(){ 37 | String ls="var numberBi=\""+numberBi+"\";"+ 38 | "var numberBiEn=\""+numberBiEn+"\";"+ 39 | "var numberBiNote=\""+numberBiNote+"\";"+ 40 | "var numberBixNormal="+numberBixNormal+";"+//标准单位是最小存储单位的位数 41 | "var numberBixShow="+numberBixShow+";"+//显示的计量单位是最小存储单位的倍数,不相等的时候会缩小到指定单位(等于小数点位数) 42 | "var numberBixDian="+numberBixDian+";"+//小数点后几位,如果有小数的话 43 | "var exchangeBi=\""+exchangeBi+"\";"+ 44 | "var exchangeBiEn=\""+exchangeBiEn+"\";"+ 45 | "var exchangeBiNote=\""+exchangeBiNote+"\";"+ 46 | "var market=\""+market+"\";"+ 47 | "var exchangeBixNormal="+exchangeBixNormal+";"+//标准单位是最小存储单位的位数 48 | "var exchangeBixShow="+exchangeBixShow+";"+//显示的计量单位是最小存储单位的倍数 49 | "var exchangeBixDian="+exchangeBixDian+";"+//小数点后几位,如果有小数的话 50 | "var entrustUrlBase=\""+entrustUrlBase+"\";"; 51 | return ls; 52 | } 53 | 54 | static Map makets = new HashMap(); 55 | 56 | public static final String btcdefault = getBtcDefault().toString(); 57 | public static final String ltcdefault = getLtcDefault().toString(); 58 | public static final String btqdefault = getBtqDefault().toString(); 59 | 60 | private static Market marketObj = null; 61 | 62 | public static Market getInstance(){ 63 | if(marketObj == null){ 64 | marketObj = new Market(); 65 | } 66 | return marketObj; 67 | } 68 | 69 | 70 | public static Market getBtcDefault(){ 71 | return getMarket("btcdefault"); 72 | } 73 | 74 | public static Market getLtcDefault(){ 75 | return getMarket("ltcdefault"); 76 | } 77 | 78 | public static Market getBtqDefault(){ 79 | return getMarket("btqdefault"); 80 | } 81 | 82 | /** 83 | * 获取一个市场 84 | * @return 85 | */ 86 | public static synchronized Market getMarket(String name){ 87 | try{ 88 | Market m = makets.get(name); 89 | if(m != null){ 90 | return m; 91 | } 92 | ResourceBundle rb= ResourceBundle.getBundle(name); 93 | m=new Market(); 94 | if(name.equals("btcdefault")){ 95 | m.numberBi="比特币"; 96 | m.numberBiNote="฿"; 97 | m.exchangeBi="人民币"; 98 | m.exchangeBiNote="¥"; 99 | }else if(name.equals("ltcdefault")){ 100 | m.numberBi="莱特币"; 101 | m.numberBiNote="Ł"; 102 | m.exchangeBi="人民币"; 103 | m.exchangeBiNote="¥"; 104 | }else if(name.equals("btqdefault")){ 105 | m.numberBi="比特权"; 106 | m.numberBiNote="BTQ"; 107 | m.exchangeBi="比特币"; 108 | m.exchangeBiNote="฿"; 109 | } 110 | 111 | //m.numberBi=new String(rb.getString("numberBi").getBytes("ISO-8859-1"), "UTF-8"); 112 | m.numberBiEn=rb.getString("numberBiEn"); 113 | //m.numberBiNote=new String(rb.getString("numberBiNote").getBytes("ISO-8859-1"), "GBK"); 114 | m.numberBixNormal=Long.parseLong(rb.getString("numberBixNormal")); 115 | m.numberBixShow=Long.parseLong(rb.getString("numberBixShow")); 116 | m.numberBixDian=Integer.parseInt((rb.getString("numberBixDian"))); 117 | //m.exchangeBi=new String(rb.getString("exchangeBi").getBytes("ISO-8859-1"), "UTF-8"); 118 | m.exchangeBiEn=new String(rb.getString("exchangeBiEn").getBytes("ISO-8859-1"), "UTF-8"); 119 | //m.exchangeBiNote=rb.getString("exchangeBiNote"); 120 | m.market=rb.getString("market"); 121 | m.exchangeBixNormal=Long.parseLong(rb.getString("exchangeBixNormal")); 122 | m.exchangeBixShow=Long.parseLong(rb.getString("exchangeBixShow")); 123 | m.exchangeBixDian=Integer.parseInt(rb.getString("exchangeBixDian")); 124 | m.entrustUrlBase=rb.getString("entrustUrlBase"); 125 | m.webId=Integer.parseInt(rb.getString("webId")); 126 | m.ip=rb.getString("ip"); 127 | m.port=Integer.parseInt(rb.getString("port")); 128 | m.hashSec=rb.getString("hashSec"); 129 | m.maxPrice=Integer.parseInt(rb.getString("maxPrice")); 130 | makets.put(name, m); 131 | return m; 132 | }catch(Exception ex){ 133 | ex.printStackTrace(); 134 | return null; 135 | } 136 | } 137 | 138 | 139 | //双重格式化,保留应有的小数点位数,避免麻烦 140 | public double formatNumber(double num){ 141 | double numNew=Arith.div(num, numberBixNormal,numberBixDian); 142 | 143 | return numNew; 144 | } 145 | 146 | //反向格式化商品,用来将部分double类型的传值转化成long类型进行委托 147 | public long formatNumberLong(double num){ 148 | long numNew=Arith.mul(num, numberBixNormal,numberBixDian); 149 | 150 | return numNew; 151 | } 152 | 153 | 154 | //格式化商品,用于显示,将基础整数位的商品格式化成需要的显示 155 | public long ffNumber(long num){ 156 | double numNew=Arith.div(num, numberBixNormal,numberBixDian); 157 | numNew=Arith.mul(numNew, numberBixNormal); 158 | 159 | return Math.round(numNew); 160 | } 161 | //比如给出2345554.返回2345000 162 | public long ffMoney(long num){ 163 | double numNew=Arith.div(num, exchangeBixNormal,exchangeBixDian); 164 | numNew=Arith.mul(numNew, exchangeBixNormal); 165 | 166 | return Math.round(numNew); 167 | } 168 | 169 | //格式化金钱 3.456 变成3.45 170 | public double formatMoney(double num){ 171 | double numNew=Arith.div(num, exchangeBixNormal,exchangeBixDian); 172 | // num=parseFloat(num)/exchangeBixNormal; 173 | // if(exchangeBixNormal!=exchangeBixShow)//不等于就说明取整数的位数 174 | // return Math.floor(Math.pow(10,exchangeBixDian)*parseFloat(num)); 175 | // else 176 | // return parseFloat(num.toFixed(exchangeBixDian)); 177 | return numNew; 178 | } 179 | 180 | /** 181 | * 格式化出来一个资金和数量乘积之后的结果 182 | * @param num 183 | * @return 12300*100100000=1231230000000 格式化后为123.123 184 | */ 185 | public double formatMoneyAndNumber(double num){ 186 | double numNew=Arith.div(num, exchangeBixNormal*numberBixNormal,exchangeBixDian+numberBixDian); 187 | 188 | return numNew; 189 | } 190 | 191 | //反向格式化商品,用来将部分double类型的传值转化成long类型进行委托 3.45变成345 192 | public long formatMoneyLong(double num){ 193 | long numNew=Arith.mul(num, exchangeBixNormal,exchangeBixDian); 194 | 195 | return numNew; 196 | } 197 | 198 | /** 199 | * 格式化出来总价long形长的 200 | * @param unitPrice 201 | * @param numbers 202 | * @return 203 | */ 204 | public long formatTotalMoney(long unitPrice,long numbers){ 205 | return unitPrice*numbers; 206 | // double unitP=formatMoney(unitPrice); 207 | // 208 | // double numb=formatNumber(numbers); 209 | // 210 | // double t=Arith.mul(unitP,numb); 211 | // 212 | // t=Arith.round(t, Market.exchangeBixDian); 213 | // 214 | // t=Arith.mul(t,Market.exchangeBixNormal); 215 | // 216 | // long rt=Arith.mul(t,Market.numberBixNormal,0); 217 | // return rt; 218 | } 219 | 220 | /** 221 | * 格式化出来总价 double形用的短的 222 | * @param unitPrice 223 | * @param numbers 224 | * @return 225 | */ 226 | public double formatTotalMoneyDoule(long unitPrice,long numbers){ 227 | double unitP=formatMoney(unitPrice); 228 | 229 | double numb=formatNumber(numbers); 230 | 231 | double t=Arith.mul(unitP,numb); 232 | 233 | t=Arith.round(t, exchangeBixDian+numberBixDian); 234 | 235 | return t; 236 | } 237 | } 238 | -------------------------------------------------------------------------------- /zb_netty_client_java/src/main/java/com/zb/kits/MapSort.java: -------------------------------------------------------------------------------- 1 | package com.zb.kits; 2 | 3 | import java.net.URLEncoder; 4 | import java.util.ArrayList; 5 | import java.util.Collections; 6 | import java.util.Comparator; 7 | import java.util.HashMap; 8 | import java.util.Iterator; 9 | import java.util.List; 10 | import java.util.Map; 11 | import java.util.Map.Entry; 12 | import java.util.TreeMap; 13 | 14 | import com.sun.xml.internal.ws.util.StringUtils; 15 | 16 | public class MapSort { 17 | 18 | /** 19 | * 20 | * 方法用途: 对所有传入参数按照字段名的 ASCII 码从小到大排序(字典序),并且生成url参数串
21 | * 实现步骤:
22 | * 23 | * @param paraMap 24 | * 要排序的Map对象 25 | * @param urlEncode 26 | * 是否需要URLENCODE 27 | * @param keyToLower 28 | * 是否需要将Key转换为全小写 true:key转化成小写,false:不转化 29 | * @return 30 | */ 31 | public static String formatUrlMap(Map paraMap, boolean urlEncode, boolean keyToLower) { 32 | String buff = ""; 33 | Map tmpMap = paraMap; 34 | try { 35 | List> infoIds = new ArrayList>(tmpMap.entrySet()); 36 | // 对所有传入参数按照字段名的 ASCII 码从小到大排序(字典序) 37 | Collections.sort(infoIds, new Comparator>() { 38 | 39 | @Override 40 | public int compare(Map.Entry o1, Map.Entry o2) { 41 | return (o1.getKey()).toString().compareTo(o2.getKey()); 42 | } 43 | }); 44 | // 构造URL 键值对的格式 45 | StringBuilder buf = new StringBuilder(); 46 | for (Map.Entry item : infoIds) { 47 | 48 | String key = item.getKey(); 49 | String val = item.getValue(); 50 | if (urlEncode) { 51 | val = URLEncoder.encode(val, "utf-8"); 52 | } 53 | if (keyToLower) { 54 | buf.append(key.toLowerCase() + "=" + val); 55 | } else { 56 | buf.append(key + "=" + val); 57 | } 58 | buf.append("&"); 59 | 60 | 61 | } 62 | buff = buf.toString(); 63 | if (buff.isEmpty() == false) { 64 | buff = buff.substring(0, buff.length() - 1); 65 | } 66 | } catch (Exception e) { 67 | return null; 68 | } 69 | return buff; 70 | } 71 | 72 | public static void main(String[] args) { 73 | 74 | Map map = new HashMap(); 75 | 76 | map.put("Kb", "K"); 77 | map.put("Wc", "W"); 78 | map.put("Ab", "A"); 79 | map.put("ad", "a"); 80 | map.put("Fe", "N"); 81 | map.put("Bf", "B"); 82 | map.put("Cg", "C"); 83 | map.put("Zh", "Z"); 84 | 85 | Map resultMap = sortMapByKey(map); // 按Key进行排序,根据首字母hashcode 86 | 87 | for (Map.Entry entry : resultMap.entrySet()) { 88 | System.out.println(entry.getKey() + " " + entry.getValue()); 89 | } 90 | 91 | } 92 | 93 | /** 94 | * 使用 Map按key首字母hashcode进行排序 95 | * 96 | * @param map 97 | * @return 98 | */ 99 | public static Map sortMapByKey(Map map) { 100 | if (map == null || map.isEmpty()) { 101 | return null; 102 | } 103 | 104 | Map sortMap = new TreeMap(new MapKeyComparator()); 105 | 106 | sortMap.putAll(map); 107 | 108 | return sortMap; 109 | } 110 | 111 | public static String toStringMap(Map m) { 112 | // 按map键首字母顺序进行排序 113 | m = MapSort.sortMapByKey(m); 114 | 115 | StringBuilder sbl = new StringBuilder(); 116 | for (Iterator i = m.entrySet().iterator(); i.hasNext();) { 117 | Entry e = i.next(); 118 | Object o = e.getValue(); 119 | String v = ""; 120 | if (o == null) { 121 | v = ""; 122 | } else if (o instanceof String[]) { 123 | String[] s = (String[]) o; 124 | if (s.length > 0) { 125 | v = s[0]; 126 | } 127 | } else { 128 | v = o.toString(); 129 | } 130 | if (!e.getKey().equals("sign") && !e.getKey().equals("reqTime") && !e.getKey().equals("tx")) { 131 | // try { 132 | // sbl.append("&").append(e.getKey()).append("=").append(URLEncoder.encode(v, 133 | // "utf-8")); 134 | // } catch (UnsupportedEncodingException e1) { 135 | // e1.printStackTrace(); 136 | sbl.append("&").append(e.getKey()).append("=").append(v); 137 | // } 138 | } 139 | } 140 | String s = sbl.toString(); 141 | if (s.length() > 0) { 142 | return s.substring(1); 143 | } 144 | return ""; 145 | } 146 | } 147 | 148 | class MapKeyComparator implements Comparator { 149 | 150 | public int compare(String str1, String str2) { 151 | 152 | return str1.compareTo(str2); 153 | } 154 | } -------------------------------------------------------------------------------- /zb_netty_client_java/src/main/java/websocketx/client/EncryDigestUtil.java: -------------------------------------------------------------------------------- 1 | package websocketx.client; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | import java.security.MessageDigest; 5 | import java.security.NoSuchAlgorithmException; 6 | import java.util.Arrays; 7 | 8 | public class EncryDigestUtil { 9 | 10 | private final static String encodingCharset = "UTF-8"; 11 | 12 | /** 13 | * 生成签名消息 14 | * @param aValue 要签名的字符 15 | * @param aKey 签名密钥 16 | * @return 17 | */ 18 | public static String hmacSign(String aValue, String aKey) { 19 | byte k_ipad[] = new byte[64]; 20 | byte k_opad[] = new byte[64]; 21 | byte keyb[]; 22 | byte value[]; 23 | try { 24 | keyb = aKey.getBytes(encodingCharset); 25 | value = aValue.getBytes(encodingCharset); 26 | } catch (UnsupportedEncodingException e) { 27 | keyb = aKey.getBytes(); 28 | value = aValue.getBytes(); 29 | } 30 | 31 | Arrays.fill(k_ipad, keyb.length, 64, (byte) 54); 32 | Arrays.fill(k_opad, keyb.length, 64, (byte) 92); 33 | for (int i = 0; i < keyb.length; i++) { 34 | k_ipad[i] = (byte) (keyb[i] ^ 0x36); 35 | k_opad[i] = (byte) (keyb[i] ^ 0x5c); 36 | } 37 | 38 | MessageDigest md = null; 39 | try { 40 | md = MessageDigest.getInstance("MD5"); 41 | } catch (NoSuchAlgorithmException e) { 42 | 43 | return null; 44 | } 45 | md.update(k_ipad); 46 | md.update(value); 47 | byte dg[] = md.digest(); 48 | md.reset(); 49 | md.update(k_opad); 50 | md.update(dg, 0, 16); 51 | dg = md.digest(); 52 | return toHex(dg); 53 | } 54 | 55 | public static String toHex(byte input[]) { 56 | if (input == null) 57 | return null; 58 | StringBuffer output = new StringBuffer(input.length * 2); 59 | for (int i = 0; i < input.length; i++) { 60 | int current = input[i] & 0xff; 61 | if (current < 16) 62 | output.append("0"); 63 | output.append(Integer.toString(current, 16)); 64 | } 65 | 66 | return output.toString(); 67 | } 68 | 69 | /** 70 | * 71 | * @param args 72 | * @param key 73 | * @return 74 | */ 75 | public static String getHmac(String[] args, String key) { 76 | if (args == null || args.length == 0) { 77 | return (null); 78 | } 79 | StringBuffer str = new StringBuffer(); 80 | for (int i = 0; i < args.length; i++) { 81 | str.append(args[i]); 82 | } 83 | return (hmacSign(str.toString(), key)); 84 | } 85 | 86 | /** 87 | * SHA加密 88 | * @param aValue 89 | * @return 90 | */ 91 | public static String digest(String aValue) { 92 | aValue = aValue.trim(); 93 | byte value[]; 94 | try { 95 | value = aValue.getBytes(encodingCharset); 96 | } catch (UnsupportedEncodingException e) { 97 | value = aValue.getBytes(); 98 | } 99 | MessageDigest md = null; 100 | try { 101 | md = MessageDigest.getInstance("SHA"); 102 | } catch (NoSuchAlgorithmException e) { 103 | e.printStackTrace(); 104 | return null; 105 | } 106 | return toHex(md.digest(value)); 107 | 108 | } 109 | 110 | // public static void main(String[] args) { 111 | // System.out.println(hmacSign("AnnulCard1000043252120080620160450.0http://localhost/SZXpro/callback.asp�?4564868265473632445648682654736324511","8UPp0KE8sq73zVP370vko7C39403rtK1YwX40Td6irH216036H27Eb12792t")); 112 | // } 113 | } 114 | -------------------------------------------------------------------------------- /zb_netty_client_java/src/main/java/websocketx/client/RunExample.java: -------------------------------------------------------------------------------- 1 | package websocketx.client; 2 | 3 | import org.apache.log4j.Logger; 4 | 5 | public class RunExample { 6 | 7 | private static Logger log = Logger.getLogger(RunExample.class); 8 | 9 | public static WebSocketClient client; 10 | 11 | public static void main(String[] args) { 12 | try { 13 | if(client==null){ 14 | log.info("链接到"+WebSocketClient.serverUrl); 15 | client = new WebSocketClient( WebSocketClient.serverUrl ); 16 | } 17 | client.connect(); 18 | log.info("================================"+client.isAlive()); 19 | client.doTask(); 20 | } catch (Exception e) { 21 | // TODO Auto-generated catch block 22 | e.printStackTrace(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /zb_netty_client_java/src/main/java/websocketx/client/WebSocketClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package websocketx.client; 17 | 18 | import io.netty.bootstrap.Bootstrap; 19 | import io.netty.channel.Channel; 20 | import io.netty.channel.ChannelException; 21 | import io.netty.channel.ChannelInitializer; 22 | import io.netty.channel.ChannelPipeline; 23 | import io.netty.channel.EventLoopGroup; 24 | import io.netty.channel.nio.NioEventLoopGroup; 25 | import io.netty.channel.socket.SocketChannel; 26 | import io.netty.channel.socket.nio.NioSocketChannel; 27 | import io.netty.handler.codec.http.DefaultHttpHeaders; 28 | import io.netty.handler.codec.http.HttpClientCodec; 29 | import io.netty.handler.codec.http.HttpObjectAggregator; 30 | import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; 31 | import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory; 32 | import io.netty.handler.codec.http.websocketx.WebSocketVersion; 33 | import io.netty.handler.ssl.SslContext; 34 | import io.netty.handler.ssl.SslContextBuilder; 35 | import io.netty.handler.ssl.util.InsecureTrustManagerFactory; 36 | 37 | import java.math.BigDecimal; 38 | import java.net.URI; 39 | import java.nio.channels.UnsupportedAddressTypeException; 40 | import java.util.HashMap; 41 | import java.util.Map; 42 | 43 | import com.alibaba.fastjson.JSONObject; 44 | import com.zb.kits.MapSort; 45 | 46 | public class WebSocketClient { 47 | private String url; 48 | private EventLoopGroup group; 49 | private Channel channel; 50 | 51 | public final String accessKey = ""; 52 | public final String secretKey = ""; 53 | public static String serverUrl = "wss://api.zb.com:9999/websocket"; 54 | public static String payPass = "xxxxxxxxx"; 55 | 56 | public WebSocketClient(String url){ 57 | this.url=url; 58 | } 59 | 60 | public void connect() throws Exception { 61 | if (url == null || "".equals(url.trim())) { 62 | throw new NullPointerException("the url can not be empty"); 63 | } 64 | URI uri = new URI(url); 65 | String scheme = uri.getScheme() == null ? "http" : uri.getScheme(); 66 | final String host = uri.getHost() == null ? "127.0.0.1" : uri.getHost(); 67 | final int port; 68 | if (uri.getPort() == -1) { 69 | if ("http".equalsIgnoreCase(scheme)) { 70 | port = 80; 71 | } else if ("wss".equalsIgnoreCase(scheme)) { 72 | port = 443; 73 | } else { 74 | port = -1; 75 | } 76 | } else { 77 | port = uri.getPort(); 78 | } 79 | 80 | if (!"ws".equalsIgnoreCase(scheme) && !"wss".equalsIgnoreCase(scheme)) { 81 | System.err.println("Only WS(S) is supported."); 82 | throw new UnsupportedAddressTypeException(); 83 | } 84 | final boolean ssl = "wss".equalsIgnoreCase(scheme); 85 | final SslContext sslCtx; 86 | if (ssl) { 87 | sslCtx = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build(); 88 | } else { 89 | sslCtx = null; 90 | } 91 | group = new NioEventLoopGroup(); 92 | try { 93 | final WebSocketClientHandler handler = new WebSocketClientHandler( 94 | WebSocketClientHandshakerFactory.newHandshaker(uri, 95 | WebSocketVersion.V13, null, false, 96 | new DefaultHttpHeaders())) { 97 | @Override 98 | public void onReceive(String msg) { 99 | System.out.println("channel获取消息:" + msg); 100 | } 101 | }; 102 | Bootstrap b = new Bootstrap(); 103 | b.group(group).channel(NioSocketChannel.class) 104 | .handler(new ChannelInitializer() { 105 | @Override 106 | protected void initChannel(SocketChannel ch) { 107 | ChannelPipeline p = ch.pipeline(); 108 | if (sslCtx != null) { 109 | p.addLast(sslCtx.newHandler(ch.alloc(), host, 110 | port)); 111 | } 112 | p.addLast(new HttpClientCodec(), 113 | new HttpObjectAggregator(8192), handler); 114 | } 115 | }); 116 | 117 | channel = b.connect(uri.getHost(), port).sync().channel(); 118 | // ChannelFuture f = channel.closeFuture().await(); 119 | handler.handshakeFuture().sync(); 120 | } catch (Exception e) { 121 | this.cancel(); 122 | throw e; 123 | } 124 | } 125 | 126 | /** 127 | * 订阅频道(仅限公共频道) 128 | * @param channel 129 | * @throws ChannelException 130 | */ 131 | public void addChannel(String channel)throws ChannelException{ 132 | if(!isAlive())throw new ChannelException("the channel is not active"); 133 | JSONObject data=new JSONObject(); 134 | data.put("event", "addChannel"); 135 | data.put("channel", channel); 136 | 137 | System.out.println(data); 138 | 139 | this.channel.writeAndFlush(new TextWebSocketFrame(data.toString())); 140 | } 141 | 142 | /** 143 | * 取消订阅(仅限公共频道) 144 | * @param channel 145 | * @param currency 146 | * @throws ChannelException 147 | */ 148 | public void removeChannel(String channel,String currency)throws ChannelException{ 149 | if(!isAlive())throw new ChannelException("the channel is not active"); 150 | this.channel.writeAndFlush(new TextWebSocketFrame("{'event':'removeChannel','channel':'"+channel+"'}")); 151 | } 152 | 153 | /** 154 | * 委托下单 155 | * @param accessKey 156 | * @param secretKey 157 | * @param price 158 | * @param amount 159 | * @param coin 160 | * @param tradeType 1buy 161 | * @throws Exception 162 | */ 163 | public void order(double price,double amount,String coin, int tradeType)throws Exception{ 164 | if(!isAlive())throw new ChannelException("the channel is not active"); 165 | 166 | JSONObject data=new JSONObject(); 167 | data.put("event", "addChannel"); 168 | data.put("channel", coin.toLowerCase()+"_order"); 169 | data.put("accesskey", accessKey); 170 | data.put("price", price); 171 | data.put("amount", amount); 172 | data.put("tradeType", tradeType); 173 | 174 | String secret = EncryDigestUtil.digest(secretKey); 175 | String sign = EncryDigestUtil.hmacSign(data.toString(), secret); 176 | 177 | data.put("sign", sign); 178 | 179 | System.out.println(data.toString()); 180 | 181 | this.channel.writeAndFlush(new TextWebSocketFrame(data.toString())); 182 | } 183 | 184 | /** 185 | * 取消委托 186 | * @param accessKey 187 | * @param secretKey 188 | * @param id 189 | * @param coin 190 | * @throws Exception 191 | */ 192 | public void cancelOrder(long id,String coin) throws Exception{ 193 | if(!isAlive())throw new ChannelException("the channel is not active"); 194 | 195 | JSONObject data=new JSONObject(); 196 | data.put("event", "addChannel"); 197 | data.put("channel", coin.toLowerCase()+"_cancelorder"); 198 | data.put("accesskey", accessKey); 199 | data.put("id", id); 200 | 201 | String secret = EncryDigestUtil.digest(secretKey); 202 | String sign = EncryDigestUtil.hmacSign(data.toString(), secret); 203 | 204 | data.put("sign", sign); 205 | 206 | System.out.println(data); 207 | this.channel.writeAndFlush(new TextWebSocketFrame(data.toString())); 208 | } 209 | 210 | /** 211 | * 获取委托买单或卖单 212 | * @param accessKey 213 | * @param secretKey 214 | * @param id 215 | * @param coin 216 | * @throws Exception 217 | */ 218 | public void getOrder(long id,String coin) throws Exception{ 219 | if(!isAlive())throw new ChannelException("the channel is not active"); 220 | 221 | JSONObject data=new JSONObject(); 222 | data.put("event", "addChannel"); 223 | data.put("channel", coin.toLowerCase()+"_getorder"); 224 | data.put("accesskey", accessKey); 225 | data.put("id", id); 226 | 227 | String secret = EncryDigestUtil.digest(secretKey); 228 | String sign = EncryDigestUtil.hmacSign(data.toString(), secret); 229 | 230 | data.put("sign", sign); 231 | 232 | System.out.println(data); 233 | this.channel.writeAndFlush(new TextWebSocketFrame(data.toString())); 234 | } 235 | 236 | /** 237 | * 获取多个委托买单或卖单,每次请求返回10条记录 238 | * @param accessKey 239 | * @param secretKey 240 | * @param pageIndex 241 | * @param coin 242 | * @throws Exception 243 | */ 244 | public void getOrders(int pageIndex,int tradeType, String coin) throws Exception{ 245 | if(!isAlive())throw new ChannelException("the channel is not active"); 246 | 247 | JSONObject data=new JSONObject(); 248 | data.put("event", "addChannel"); 249 | data.put("channel", coin.toLowerCase()+"_getorders"); 250 | data.put("accesskey", accessKey); 251 | data.put("tradeType", tradeType); 252 | data.put("pageIndex", pageIndex); 253 | 254 | String secret = EncryDigestUtil.digest(secretKey); 255 | String sign = EncryDigestUtil.hmacSign(data.toString(), secret); 256 | 257 | data.put("sign", sign); 258 | 259 | System.out.println(data); 260 | this.channel.writeAndFlush(new TextWebSocketFrame(data.toString())); 261 | } 262 | 263 | /** 264 | * (新)获取多个委托买单或卖单,每次请求返回pageSize<=100条记录 265 | * @param accessKey 266 | * @param secretKey 267 | * @param pageIndex 268 | * @param pageSize 269 | * @param coin 270 | * @throws Exception 271 | */ 272 | public void getOrdersNew(int pageIndex,int pageSize,int tradeType,String coin) throws Exception{ 273 | if(!isAlive())throw new ChannelException("the channel is not active"); 274 | 275 | JSONObject data=new JSONObject(); 276 | data.put("event", "addChannel"); 277 | data.put("channel", coin.toLowerCase()+"_getordersnew"); 278 | data.put("accesskey", accessKey); 279 | data.put("tradeType", tradeType); 280 | data.put("pageIndex", pageIndex); 281 | data.put("pageSize", pageSize); 282 | 283 | String secret = EncryDigestUtil.digest(secretKey); 284 | String sign = EncryDigestUtil.hmacSign(data.toString(), secret); 285 | 286 | data.put("sign", sign); 287 | 288 | System.out.println(data); 289 | this.channel.writeAndFlush(new TextWebSocketFrame(data.toString())); 290 | } 291 | 292 | /** 293 | * 与getOrdersNew的区别是取消tradeType字段过滤,可同时获取买单和卖单,每次请求返回pageSize<=100条记录 294 | * @param accessKey 295 | * @param secretKey 296 | * @param pageIndex 297 | * @param pageSize 298 | * @param coin 299 | * @throws Exception 300 | */ 301 | public void getOrdersIgnoreTradeType(int pageIndex,int pageSize,String coin) throws Exception{ 302 | if(!isAlive())throw new ChannelException("the channel is not active"); 303 | 304 | JSONObject data=new JSONObject(); 305 | data.put("event", "addChannel"); 306 | data.put("channel", coin.toLowerCase()+"_getordersignoretradetype"); 307 | data.put("accesskey", accessKey); 308 | data.put("pageIndex", pageIndex); 309 | data.put("pageSize", pageSize); 310 | 311 | String secret = EncryDigestUtil.digest(secretKey); 312 | System.out.println("getOrdersIgnoreTradeType:" + data.toString()); 313 | String sign = EncryDigestUtil.hmacSign(data.toString(), secret); 314 | 315 | data.put("sign", sign); 316 | 317 | System.out.println(data); 318 | this.channel.writeAndFlush(new TextWebSocketFrame(data.toString())); 319 | } 320 | 321 | /** 322 | * 获取未成交或部份成交的买单和卖单,每次请求返回pageSize<=100条记录 323 | * @param accessKey 324 | * @param secretKey 325 | * @param pageIndex 326 | * @param pageSize 327 | * @param coin 328 | * @throws Exception 329 | */ 330 | public void getUnfinishedOrdersIgnoreTradeType(int pageIndex,int pageSize,String coin) throws Exception{ 331 | if(!isAlive())throw new ChannelException("the channel is not active"); 332 | 333 | JSONObject data=new JSONObject(); 334 | data.put("event", "addChannel"); 335 | data.put("channel", coin.toLowerCase()+"_getunfinishedordersignoretradetype"); 336 | data.put("accesskey", accessKey); 337 | data.put("pageIndex", pageIndex); 338 | data.put("pageSize", pageSize); 339 | 340 | String secret = EncryDigestUtil.digest(secretKey); 341 | String sign = EncryDigestUtil.hmacSign(data.toString(), secret); 342 | 343 | data.put("sign", sign); 344 | 345 | System.out.println(data); 346 | this.channel.writeAndFlush(new TextWebSocketFrame(data.toString())); 347 | } 348 | 349 | /** 350 | * 获取某个币种的充值地址 351 | * @param accessKey 352 | * @param coin 353 | * @throws Exception 354 | */ 355 | public void getUserAddress(String coin) throws Exception{ 356 | if(!isAlive())throw new ChannelException("the channel is not active"); 357 | 358 | JSONObject data=new JSONObject(); 359 | data.put("event", "addChannel"); 360 | data.put("channel", coin.toLowerCase()+"_getuseraddress"); 361 | data.put("accesskey", accessKey); 362 | 363 | String secret = EncryDigestUtil.digest(secretKey); 364 | String sign = EncryDigestUtil.hmacSign(data.toString(), secret); 365 | 366 | data.put("sign", sign); 367 | 368 | System.out.println(data); 369 | this.channel.writeAndFlush(new TextWebSocketFrame(data.toString())); 370 | } 371 | 372 | /** 373 | * 获取认证的提现地址 374 | * @param accessKey 375 | * @param coin 376 | * @throws Exception 377 | */ 378 | public void getWithdrawAddress(String coin) throws Exception{ 379 | if(!isAlive())throw new ChannelException("the channel is not active"); 380 | 381 | JSONObject data=new JSONObject(); 382 | data.put("event", "addChannel"); 383 | data.put("channel", coin.toLowerCase()+"_getwithdrawaddress"); 384 | data.put("accesskey", accessKey); 385 | 386 | String secret = EncryDigestUtil.digest(secretKey); 387 | String sign = EncryDigestUtil.hmacSign(data.toString(), secret); 388 | 389 | data.put("sign", sign); 390 | 391 | System.out.println(data); 392 | this.channel.writeAndFlush(new TextWebSocketFrame(data.toString())); 393 | } 394 | 395 | /** 396 | * 获取提现的记录 397 | * @param accessKey 398 | * @param coin 399 | * @throws Exception 400 | */ 401 | public void getWithdrawRecord(String coin, int pageIndex, int pageSize) throws Exception{ 402 | if(!isAlive())throw new ChannelException("the channel is not active"); 403 | 404 | JSONObject data=new JSONObject(); 405 | data.put("event", "addChannel"); 406 | data.put("channel", coin.toLowerCase()+"_getwithdrawrecord"); 407 | data.put("accesskey", accessKey); 408 | data.put("pageIndex", pageIndex); 409 | data.put("pageSize", pageSize); 410 | 411 | String secret = EncryDigestUtil.digest(secretKey); 412 | String sign = EncryDigestUtil.hmacSign(data.toString(), secret); 413 | 414 | data.put("sign", sign); 415 | 416 | System.out.println(data); 417 | this.channel.writeAndFlush(new TextWebSocketFrame(data.toString())); 418 | } 419 | 420 | /** 421 | * 取消提现 422 | * @param accessKey 423 | * @param coin 424 | * @throws Exception 425 | */ 426 | public void cancelWithdraw(String coin, String downloadId) throws Exception{ 427 | if(!isAlive())throw new ChannelException("the channel is not active"); 428 | 429 | JSONObject data=new JSONObject(); 430 | data.put("event", "addChannel"); 431 | data.put("channel", coin.toLowerCase()+"_cancelwithdraw"); 432 | data.put("accesskey", accessKey); 433 | data.put("downloadId", downloadId); 434 | data.put("safePwd", payPass); 435 | 436 | String secret = EncryDigestUtil.digest(secretKey); 437 | String sign = EncryDigestUtil.hmacSign(data.toString(), secret); 438 | 439 | data.put("sign", sign); 440 | 441 | System.out.println(data); 442 | this.channel.writeAndFlush(new TextWebSocketFrame(data.toString())); 443 | } 444 | 445 | /** 446 | * 提现 447 | * @param coin 币种 448 | * @param amount 提现金额 449 | * @param fees 提现矿工费 450 | * @param receiveAddr 提现地址 451 | * @throws Exception 452 | */ 453 | public void withdraw(String coin, BigDecimal amount, BigDecimal fees, String receiveAddr) throws Exception{ 454 | if(!isAlive())throw new ChannelException("the channel is not active"); 455 | 456 | JSONObject data=new JSONObject(); 457 | data.put("event", "addChannel"); 458 | data.put("channel", coin.toLowerCase()+"_withdraw"); 459 | data.put("accesskey", accessKey); 460 | data.put("amount", amount+""); 461 | data.put("fees", fees+""); 462 | data.put("receiveAddr", receiveAddr); 463 | data.put("safePwd", payPass); 464 | 465 | String secret = EncryDigestUtil.digest(secretKey); 466 | String sign = EncryDigestUtil.hmacSign(data.toString(), secret); 467 | 468 | data.put("sign", sign); 469 | 470 | System.out.println(data); 471 | this.channel.writeAndFlush(new TextWebSocketFrame(data.toString())); 472 | } 473 | 474 | /** 475 | * 获取用户资金信息 476 | * @param accessKey 477 | * @param secretKey 478 | */ 479 | public void getAccountInfo(){ 480 | JSONObject data=new JSONObject(); 481 | data.put("event", "addChannel"); 482 | data.put("channel","getaccountinfo"); 483 | data.put("accesskey", accessKey); 484 | data.put("no", null); 485 | 486 | String secret = EncryDigestUtil.digest(secretKey); 487 | String sign = EncryDigestUtil.hmacSign(data.toString(), secret); 488 | 489 | data.put("sign", sign); 490 | 491 | System.out.println(data); 492 | this.channel.writeAndFlush(new TextWebSocketFrame(data.toString())); 493 | } 494 | 495 | /** 496 | * 注销客户端 497 | */ 498 | public void cancel(){ 499 | if(group!=null)group.shutdownGracefully(); 500 | } 501 | /** 502 | * 判断客户端是否保持激活状态 503 | * @return 504 | */ 505 | public boolean isAlive(){ 506 | return this.channel!=null&&this.channel.isActive()?true:false; 507 | } 508 | 509 | /** 510 | * 测试帐号: 511 | * API访问密匙(Access Key): d31f15d5-xxxx-xxxx-xxxx-5ab5e6326b2e 512 | * API私有密匙(Secret Key): c1639fa5-xxxx-xxxx-xxxx-f42759830a19[仅显示一次] 513 | * @param args 514 | * @throws Exception 515 | */ 516 | public void doTask() throws Exception { 517 | System.out.println("websocket通讯地址:" + serverUrl); 518 | WebSocketClient client=new WebSocketClient(System.getProperty ("url", serverUrl)); 519 | try { 520 | client.connect(); 521 | System.out.println("================================"+client.isAlive()); 522 | // client.addChannel("ltcbtc_ticker");//通过 523 | // client.addChannel("ltcbtc_depth");//通过 524 | // client.addChannel("ltcbtc_trades");//通过 525 | 526 | // client.order( 0.019258, 1, "ethbtc", 0); 527 | // client.order( 0.009258, 1, "ltcbtc", 1); 528 | // client.cancelOrder(20151006160133624L , "ethbtc"); 529 | // client.getOrder(20151006160133556L , "ethbtc"); 530 | // client.getOrders(1,1 , "ethbtc"); 531 | // client.getOrdersIgnoreTradeType(1,10 , "ethbtc"); 532 | // client.getUnfinishedOrdersIgnoreTradeType(1,10 , "ethbtc"); 533 | // client.getOrdersNew( 1,10, 1, "ethbtc"); 534 | client.cancelWithdraw("ethbtc", "20160425916"); 535 | 536 | // client.getAccountInfo(); 537 | } catch (Exception e) { 538 | // TODO Auto-generated catch block 539 | e.printStackTrace(); 540 | } 541 | // } 542 | } 543 | 544 | } 545 | -------------------------------------------------------------------------------- /zb_netty_client_java/src/main/java/websocketx/client/WebSocketClientHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | //The MIT License 17 | // 18 | //Copyright (c) 2009 Carl Bystršm 19 | // 20 | //Permission is hereby granted, free of charge, to any person obtaining a copy 21 | //of this software and associated documentation files (the "Software"), to deal 22 | //in the Software without restriction, including without limitation the rights 23 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 24 | //copies of the Software, and to permit persons to whom the Software is 25 | //furnished to do so, subject to the following conditions: 26 | // 27 | //The above copyright notice and this permission notice shall be included in 28 | //all copies or substantial portions of the Software. 29 | // 30 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 31 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 32 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 33 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 34 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 35 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 36 | //THE SOFTWARE. 37 | 38 | package websocketx.client; 39 | 40 | import io.netty.channel.Channel; 41 | import io.netty.channel.ChannelFuture; 42 | import io.netty.channel.ChannelHandlerContext; 43 | import io.netty.channel.ChannelPromise; 44 | import io.netty.channel.SimpleChannelInboundHandler; 45 | import io.netty.handler.codec.http.FullHttpResponse; 46 | import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame; 47 | import io.netty.handler.codec.http.websocketx.PongWebSocketFrame; 48 | import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; 49 | import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker; 50 | import io.netty.handler.codec.http.websocketx.WebSocketFrame; 51 | import io.netty.util.CharsetUtil; 52 | 53 | public abstract class WebSocketClientHandler extends SimpleChannelInboundHandler{ 54 | 55 | private final WebSocketClientHandshaker handshaker; 56 | private ChannelPromise handshakeFuture; 57 | 58 | public WebSocketClientHandler(WebSocketClientHandshaker handshaker) { 59 | this.handshaker = handshaker; 60 | } 61 | 62 | public ChannelFuture handshakeFuture() { 63 | return handshakeFuture; 64 | } 65 | 66 | @Override 67 | public void handlerAdded(ChannelHandlerContext ctx) { 68 | handshakeFuture = ctx.newPromise(); 69 | } 70 | 71 | @Override 72 | public void channelActive(ChannelHandlerContext ctx) { 73 | handshaker.handshake(ctx.channel()); 74 | } 75 | 76 | @Override 77 | public void channelInactive(ChannelHandlerContext ctx) { 78 | System.out.println("WebSocket Client disconnected!"); 79 | do{ 80 | if(RunExample.client!=null){ 81 | try { 82 | RunExample.client.cancel(); 83 | RunExample.client.connect(); 84 | Thread.sleep(3000); 85 | } catch (Exception e) { 86 | // TODO Auto-generated catch block 87 | e.printStackTrace(); 88 | } 89 | } 90 | }while( !RunExample.client.isAlive() ); 91 | } 92 | 93 | @Override 94 | public void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception { 95 | Channel ch = ctx.channel(); 96 | if (!handshaker.isHandshakeComplete()) { 97 | handshaker.finishHandshake(ch, (FullHttpResponse) msg); 98 | System.out.println("WebSocket Client connected!"); 99 | handshakeFuture.setSuccess(); 100 | return; 101 | } 102 | 103 | if (msg instanceof FullHttpResponse) { 104 | FullHttpResponse response = (FullHttpResponse) msg; 105 | throw new IllegalStateException( 106 | "Unexpected FullHttpResponse (getStatus=" + response.getStatus() + 107 | ", content=" + response.content().toString(CharsetUtil.UTF_8) + ')'); 108 | } 109 | 110 | WebSocketFrame frame = (WebSocketFrame) msg; 111 | if (frame instanceof TextWebSocketFrame) { 112 | TextWebSocketFrame textFrame = (TextWebSocketFrame) frame; 113 | onReceive(textFrame.text()); 114 | } else if (frame instanceof PongWebSocketFrame) { 115 | System.out.println("WebSocket Client received pong"); 116 | } else if (frame instanceof CloseWebSocketFrame) { 117 | System.out.println("WebSocket Client received closing"); 118 | ch.close(); 119 | } 120 | } 121 | 122 | @Override 123 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 124 | cause.printStackTrace(); 125 | if (!handshakeFuture.isDone()) { 126 | handshakeFuture.setFailure(cause); 127 | } 128 | ctx.close(); 129 | } 130 | 131 | public abstract void onReceive(String msg); 132 | } 133 | -------------------------------------------------------------------------------- /易语言/中币api示例.e: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zb2017/api/4927d6940c9f217c91b11c042532827897f74927/易语言/中币api示例.e -------------------------------------------------------------------------------- /易语言/精易模块5.7.ec: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zb2017/api/4927d6940c9f217c91b11c042532827897f74927/易语言/精易模块5.7.ec --------------------------------------------------------------------------------