diff --git a/.classpath b/.classpath index 64f1662..c837f30 100644 --- a/.classpath +++ b/.classpath @@ -28,5 +28,6 @@ + diff --git a/pom.xml b/pom.xml index 7d00c11..be76f35 100644 --- a/pom.xml +++ b/pom.xml @@ -144,6 +144,11 @@ 0.9.1.2 + + org.apache.httpcomponents + httpclient + 4.5.2 + useful-code diff --git a/src/main/java/osc/git/eh3/test/TestCode.java b/src/main/java/osc/git/eh3/test/TestCode.java index adcb38f..24a94e1 100644 --- a/src/main/java/osc/git/eh3/test/TestCode.java +++ b/src/main/java/osc/git/eh3/test/TestCode.java @@ -1,5 +1,7 @@ package osc.git.eh3.test; +import java.net.URLDecoder; +import java.net.URLEncoder; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Arrays; @@ -7,7 +9,11 @@ import java.util.Date; import java.util.HashSet; import java.util.Set; +import net.sf.json.JSONObject; import osc.git.eh3.utils.AESEncrypter; +import osc.git.eh3.utils.Base64; +import osc.git.eh3.utils.GeoHash; +import osc.git.eh3.utils.HttpClientUtil; public class TestCode { @@ -170,16 +176,27 @@ public class TestCode { // System.out.println(Integer.valueOf("11", 2)); - System.out.println(AESEncrypter.encrypt("lixiangrong")); - System.out.println(AESEncrypter.decrypt(AESEncrypter.encrypt("lixiangrong"))); - - System.out.println(AESEncrypter.encrypt("lixiangrong","ca048b18cac58865a8")); - System.out.println(AESEncrypter.decrypt(AESEncrypter.encrypt("lixiangrong","ca048b18cac58865a8"),"ca048b18cac58865a8")); +// System.out.println(AESEncrypter.encrypt("lixiangrong")); +// System.out.println(AESEncrypter.decrypt(AESEncrypter.encrypt("lixiangrong"))); +// +// System.out.println(AESEncrypter.encrypt("lixiangrong","ca048b18cac58865a8")); +// System.out.println(AESEncrypter.decrypt(AESEncrypter.encrypt("lixiangrong","ca048b18cac58865a8"),"ca048b18cac58865a8")); // byte[] bytes = "lixiangrong".getBytes(); // for (int i = 0; i < bytes.length; i++) { // System.out.println(bytes[i]); // } + +// System.out.println(Base64.encodeToString("lixiangrong".getBytes(), false)); + + double lon1 = 109.0145193759; + double lat1 = 34.236080797698; + System.out.println(GeoHash.encode(lat1, lon1)); + System.out.println(GeoHash.decode("wmtdgn5esrb1")[0]+" "+GeoHash.decode("wmtdgn5esrb1")[1]); + +// String url = "http://api.map.baidu.com/place/v2/search?query=银行&location=39.915,116.404&radius=2000&output=json&ak=LCG4dyrXyadeD8hFhi8SGCv6"; +// System.out.println(HttpClientUtil.sendGet(url)); + } public static Long parseDate(String s) { @@ -206,4 +223,10 @@ public class TestCode { Set tSet = new HashSet(Arrays.asList(tArray)); return tSet; } + + public static void printArrs(T[] arrs){ + for (T t : arrs) { + System.out.println(t); + } + } } \ No newline at end of file diff --git a/src/main/java/osc/git/eh3/test/TestGeoHash.java b/src/main/java/osc/git/eh3/test/TestGeoHash.java index adc68d5..b0788d1 100644 --- a/src/main/java/osc/git/eh3/test/TestGeoHash.java +++ b/src/main/java/osc/git/eh3/test/TestGeoHash.java @@ -7,23 +7,31 @@ public class TestGeoHash { public static void main(String[] args) { - double lon1 = 109.0145193757; - double lat1 = 34.236080797698; - double lon2 = 108.9644583556; - double lat2 = 34.286439088548; - double dist; - String geocode; - - dist = CommonUtils.getDistance(lon1, lat1, lon2, lat2); - System.out.println("两点相距:" + dist + " 米"); - - geocode = GeoHash.encode(lat1, lon1); - System.out.println("当前位置编码:" + geocode); - - geocode = GeoHash.encode(lat2, lon2); - System.out.println("远方位置编码:" + geocode); +// double lon1 = 109.014520; +// double lat1 = 34.236080; +// +// double lon2 = 108.9644583556; +// double lat2 = 34.286439088548; +// double dist; +// String geocode; +// +// dist = CommonUtils.getDistance(lon1, lat1, lon2, lat2); +// System.out.println("两点相距:" + dist + " 米"); +// +// geocode = GeoHash.encode(lat1, lon1); +// System.out.println("当前位置编码:" + geocode); +// +// geocode = GeoHash.encode(lat2, lon2); +// System.out.println("远方位置编码:" + geocode); +// +// System.out.println(GeoHash.decode("wqjdb8mzw7vspswfydscen0002")[0]+" "+GeoHash.decode("wqjdb8mzw7vspswfydscen0002")[1]); - System.out.println(GeoHash.decode("s6q8mc6nbupd")[0]+" "+GeoHash.decode("s6q8mc6nbupd")[1]); - + double lon1 = 112.014520; + double lat1 = 69.236080; + System.out.println(GeoHash.encode(lat1, lon1)); + + double lat = 34.236088; + double lon = 109.01455; + System.out.println(GeoHash.encode(lat, lon)); } } \ No newline at end of file diff --git a/src/main/java/osc/git/eh3/utils/Base64.java b/src/main/java/osc/git/eh3/utils/Base64.java new file mode 100644 index 0000000..8e6c2c7 --- /dev/null +++ b/src/main/java/osc/git/eh3/utils/Base64.java @@ -0,0 +1,670 @@ +package osc.git.eh3.utils; + +import java.util.Arrays; + +/** + * A very fast and memory efficient class to encode and decode to and from + * BASE64 in full accordance with RFC 2045.
+ *
+ * On Windows XP sp1 with 1.4.2_04 and later ;), this encoder and decoder is + * about 10 times faster on small arrays (10 - 1000 bytes) and 2-3 times as fast + * on larger arrays (10000 - 1000000 bytes) compared to + * sun.misc.Encoder()/Decoder().
+ *
+ * + * On byte arrays the encoder is about 20% faster than Jakarta Commons Base64 + * Codec for encode and about 50% faster for decoding large arrays. This + * implementation is about twice as fast on very small arrays (< 30 bytes). If + * source/destination is a String this version is about three times + * as fast due to the fact that the Commons Codec result has to be recoded to a + * String from byte[], which is very expensive.
+ *
+ * + * This encode/decode algorithm doesn't create any temporary arrays as many + * other codecs do, it only allocates the resulting array. This produces less + * garbage and it is possible to handle arrays twice as large as algorithms that + * create a temporary array. (E.g. Jakarta Commons Codec). It is unknown whether + * Sun's sun.misc.Encoder()/Decoder() produce temporary arrays but + * since performance is quite low it probably does.
+ *
+ * + * The encoder produces the same output as the Sun one except that the Sun's + * encoder appends a trailing line separator if the last character isn't a pad. + * Unclear why but it only adds to the length and is probably a side effect. + * Both are in conformance with RFC 2045 though.
+ * Commons codec seem to always att a trailing line separator.
+ *
+ * + * Note! The encode/decode method pairs (types) come in three versions + * with the exact same algorithm and thus a lot of code redundancy. This + * is to not create any temporary arrays for transcoding to/from different + * format types. The methods not used can simply be commented out.
+ *
+ * + * There is also a "fast" version of all decode methods that works the same way + * as the normal ones, but har a few demands on the decoded input. Normally + * though, these fast verions should be used if the source if the input is known + * and it hasn't bee tampered with.
+ *
+ * + * If you find the code useful or you find a bug, please send me a note at + * base64 @ miginfocom . com. + * + * Licence (BSD): ============== + * + * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (base64 @ miginfocom . com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. Redistributions in binary + * form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided + * with the distribution. Neither the name of the MiG InfoCom AB nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @version 2.2 + * @author Mikael Grev Date: 2004-aug-02 Time: 11:31:11 + */ + +public class Base64 { + private static final char[] CA = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray(); + private static final int[] IA = new int[256]; + + static { + Arrays.fill(IA, -1); + for (int i = 0, iS = CA.length; i < iS; i++) + IA[CA[i]] = i; + IA['='] = 0; + } + + // **************************************************************************************** + // * char[] version + // **************************************************************************************** + + /** + * Encodes a raw byte array into a BASE64 char[] representation + * i accordance with RFC 2045. + * + * @param sArr + * The bytes to convert. If null or length 0 an + * empty array will be returned. + * @param lineSep + * Optional "\r\n" after 76 characters, unless end of file.
+ * No line separator will be in breach of RFC 2045 which + * specifies max 76 per line but will be a little faster. + * @return A BASE64 encoded array. Never null. + */ + public final static char[] encodeToChar(byte[] sArr, boolean lineSep) { + // Check special case + int sLen = sArr != null ? sArr.length : 0; + if (sLen == 0) + return new char[0]; + + int eLen = (sLen / 3) * 3; // Length of even 24-bits. + int cCnt = ((sLen - 1) / 3 + 1) << 2; // Returned character count + int dLen = cCnt + (lineSep ? (cCnt - 1) / 76 << 1 : 0); // Length of + // returned + // array + char[] dArr = new char[dLen]; + + // Encode even 24-bits + for (int s = 0, d = 0, cc = 0; s < eLen;) { + // Copy next three bytes into lower 24 bits of int, paying attension + // to sign. + int i = (sArr[s++] & 0xff) << 16 | (sArr[s++] & 0xff) << 8 | (sArr[s++] & 0xff); + + // Encode the int into four chars + dArr[d++] = CA[(i >>> 18) & 0x3f]; + dArr[d++] = CA[(i >>> 12) & 0x3f]; + dArr[d++] = CA[(i >>> 6) & 0x3f]; + dArr[d++] = CA[i & 0x3f]; + + // Add optional line separator + if (lineSep && ++cc == 19 && d < dLen - 2) { + dArr[d++] = '\r'; + dArr[d++] = '\n'; + cc = 0; + } + } + + // Pad and encode last bits if source isn't even 24 bits. + int left = sLen - eLen; // 0 - 2. + if (left > 0) { + // Prepare the int + int i = ((sArr[eLen] & 0xff) << 10) | (left == 2 ? ((sArr[sLen - 1] & 0xff) << 2) : 0); + + // Set last four chars + dArr[dLen - 4] = CA[i >> 12]; + dArr[dLen - 3] = CA[(i >>> 6) & 0x3f]; + dArr[dLen - 2] = left == 2 ? CA[i & 0x3f] : '='; + dArr[dLen - 1] = '='; + } + return dArr; + } + + /** + * Decodes a BASE64 encoded char array. All illegal characters will be + * ignored and can handle both arrays with and without line separators. + * + * @param sArr + * The source array. null or length 0 will return an + * empty array. + * @return The decoded array of bytes. May be of length 0. Will be + * null if the legal characters (including '=') isn't + * divideable by 4. (I.e. definitely corrupted). + */ + public final static byte[] decode(char[] sArr) { + // Check special case + int sLen = sArr != null ? sArr.length : 0; + if (sLen == 0) + return new byte[0]; + + // Count illegal characters (including '\r', '\n') to know what size the + // returned array will be, + // so we don't have to reallocate & copy it later. + int sepCnt = 0; // Number of separator characters. (Actually illegal + // characters, but that's a bonus...) + for (int i = 0; i < sLen; i++) + // If input is "pure" (I.e. no line separators or illegal chars) + // base64 this loop can be commented out. + if (IA[sArr[i]] < 0) + sepCnt++; + + // Check so that legal chars (including '=') are evenly divideable by 4 + // as specified in RFC 2045. + if ((sLen - sepCnt) % 4 != 0) + return null; + + int pad = 0; + for (int i = sLen; i > 1 && IA[sArr[--i]] <= 0;) + if (sArr[i] == '=') + pad++; + + int len = ((sLen - sepCnt) * 6 >> 3) - pad; + + byte[] dArr = new byte[len]; // Preallocate byte[] of exact length + + for (int s = 0, d = 0; d < len;) { + // Assemble three bytes into an int from four "valid" characters. + int i = 0; + for (int j = 0; j < 4; j++) { // j only increased if a valid char + // was found. + int c = IA[sArr[s++]]; + if (c >= 0) + i |= c << (18 - j * 6); + else + j--; + } + // Add the bytes + dArr[d++] = (byte) (i >> 16); + if (d < len) { + dArr[d++] = (byte) (i >> 8); + if (d < len) + dArr[d++] = (byte) i; + } + } + return dArr; + } + + /** + * Decodes a BASE64 encoded char array that is known to be resonably well + * formatted. The method is about twice as fast as {@link #decode(char[])}. + * The preconditions are:
+ * + The array must have a line length of 76 chars OR no line separators at + * all (one line).
+ * + Line separator must be "\r\n", as specified in RFC 2045 + The array + * must not contain illegal characters within the encoded string
+ * + The array CAN have illegal characters at the beginning and end, those + * will be dealt with appropriately.
+ * + * @param sArr + * The source array. Length 0 will return an empty array. + * null will throw an exception. + * @return The decoded array of bytes. May be of length 0. + */ + public final static byte[] decodeFast(char[] sArr) { + // Check special case + int sLen = sArr.length; + if (sLen == 0) + return new byte[0]; + + int sIx = 0, eIx = sLen - 1; // Start and end index after trimming. + + // Trim illegal chars from start + while (sIx < eIx && IA[sArr[sIx]] < 0) + sIx++; + + // Trim illegal chars from end + while (eIx > 0 && IA[sArr[eIx]] < 0) + eIx--; + + // get the padding count (=) (0, 1 or 2) + int pad = sArr[eIx] == '=' ? (sArr[eIx - 1] == '=' ? 2 : 1) : 0; // Count + // '=' + // at + // end. + int cCnt = eIx - sIx + 1; // Content count including possible separators + int sepCnt = sLen > 76 ? (sArr[76] == '\r' ? cCnt / 78 : 0) << 1 : 0; + + int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded + // bytes + byte[] dArr = new byte[len]; // Preallocate byte[] of exact length + + // Decode all but the last 0 - 2 bytes. + int d = 0; + for (int cc = 0, eLen = (len / 3) * 3; d < eLen;) { + // Assemble three bytes into an int from four "valid" characters. + int i = IA[sArr[sIx++]] << 18 | IA[sArr[sIx++]] << 12 | IA[sArr[sIx++]] << 6 | IA[sArr[sIx++]]; + + // Add the bytes + dArr[d++] = (byte) (i >> 16); + dArr[d++] = (byte) (i >> 8); + dArr[d++] = (byte) i; + + // If line separator, jump over it. + if (sepCnt > 0 && ++cc == 19) { + sIx += 2; + cc = 0; + } + } + + if (d < len) { + // Decode last 1-3 bytes (incl '=') into 1-3 bytes + int i = 0; + for (int j = 0; sIx <= eIx - pad; j++) + i |= IA[sArr[sIx++]] << (18 - j * 6); + + for (int r = 16; d < len; r -= 8) + dArr[d++] = (byte) (i >> r); + } + + return dArr; + } + + // **************************************************************************************** + // * byte[] version + // **************************************************************************************** + + /** + * Encodes a raw byte array into a BASE64 byte[] representation + * i accordance with RFC 2045. + * + * @param sArr + * The bytes to convert. If null or length 0 an + * empty array will be returned. + * @param lineSep + * Optional "\r\n" after 76 characters, unless end of file.
+ * No line separator will be in breach of RFC 2045 which + * specifies max 76 per line but will be a little faster. + * @return A BASE64 encoded array. Never null. + */ + public final static byte[] encodeToByte(byte[] sArr, boolean lineSep) { + // Check special case + int sLen = sArr != null ? sArr.length : 0; + if (sLen == 0) + return new byte[0]; + + int eLen = (sLen / 3) * 3; // Length of even 24-bits. + int cCnt = ((sLen - 1) / 3 + 1) << 2; // Returned character count + int dLen = cCnt + (lineSep ? (cCnt - 1) / 76 << 1 : 0); // Length of + // returned + // array + byte[] dArr = new byte[dLen]; + + // Encode even 24-bits + for (int s = 0, d = 0, cc = 0; s < eLen;) { + // Copy next three bytes into lower 24 bits of int, paying attension + // to sign. + int i = (sArr[s++] & 0xff) << 16 | (sArr[s++] & 0xff) << 8 | (sArr[s++] & 0xff); + + // Encode the int into four chars + dArr[d++] = (byte) CA[(i >>> 18) & 0x3f]; + dArr[d++] = (byte) CA[(i >>> 12) & 0x3f]; + dArr[d++] = (byte) CA[(i >>> 6) & 0x3f]; + dArr[d++] = (byte) CA[i & 0x3f]; + + // Add optional line separator + if (lineSep && ++cc == 19 && d < dLen - 2) { + dArr[d++] = '\r'; + dArr[d++] = '\n'; + cc = 0; + } + } + + // Pad and encode last bits if source isn't an even 24 bits. + int left = sLen - eLen; // 0 - 2. + if (left > 0) { + // Prepare the int + int i = ((sArr[eLen] & 0xff) << 10) | (left == 2 ? ((sArr[sLen - 1] & 0xff) << 2) : 0); + + // Set last four chars + dArr[dLen - 4] = (byte) CA[i >> 12]; + dArr[dLen - 3] = (byte) CA[(i >>> 6) & 0x3f]; + dArr[dLen - 2] = left == 2 ? (byte) CA[i & 0x3f] : (byte) '='; + dArr[dLen - 1] = '='; + } + return dArr; + } + + /** + * Decodes a BASE64 encoded byte array. All illegal characters will be + * ignored and can handle both arrays with and without line separators. + * + * @param sArr + * The source array. Length 0 will return an empty array. + * null will throw an exception. + * @return The decoded array of bytes. May be of length 0. Will be + * null if the legal characters (including '=') isn't + * divideable by 4. (I.e. definitely corrupted). + */ + public final static byte[] decode(byte[] sArr) { + // Check special case + int sLen = sArr.length; + + // Count illegal characters (including '\r', '\n') to know what size the + // returned array will be, + // so we don't have to reallocate & copy it later. + int sepCnt = 0; // Number of separator characters. (Actually illegal + // characters, but that's a bonus...) + for (int i = 0; i < sLen; i++) + // If input is "pure" (I.e. no line separators or illegal chars) + // base64 this loop can be commented out. + if (IA[sArr[i] & 0xff] < 0) + sepCnt++; + + // Check so that legal chars (including '=') are evenly divideable by 4 + // as specified in RFC 2045. + if ((sLen - sepCnt) % 4 != 0) + return null; + + int pad = 0; + for (int i = sLen; i > 1 && IA[sArr[--i] & 0xff] <= 0;) + if (sArr[i] == '=') + pad++; + + int len = ((sLen - sepCnt) * 6 >> 3) - pad; + + byte[] dArr = new byte[len]; // Preallocate byte[] of exact length + + for (int s = 0, d = 0; d < len;) { + // Assemble three bytes into an int from four "valid" characters. + int i = 0; + for (int j = 0; j < 4; j++) { // j only increased if a valid char + // was found. + int c = IA[sArr[s++] & 0xff]; + if (c >= 0) + i |= c << (18 - j * 6); + else + j--; + } + + // Add the bytes + dArr[d++] = (byte) (i >> 16); + if (d < len) { + dArr[d++] = (byte) (i >> 8); + if (d < len) + dArr[d++] = (byte) i; + } + } + + return dArr; + } + + /** + * Decodes a BASE64 encoded byte array that is known to be resonably well + * formatted. The method is about twice as fast as {@link #decode(byte[])}. + * The preconditions are:
+ * + The array must have a line length of 76 chars OR no line separators at + * all (one line).
+ * + Line separator must be "\r\n", as specified in RFC 2045 + The array + * must not contain illegal characters within the encoded string
+ * + The array CAN have illegal characters at the beginning and end, those + * will be dealt with appropriately.
+ * + * @param sArr + * The source array. Length 0 will return an empty array. + * null will throw an exception. + * @return The decoded array of bytes. May be of length 0. + */ + public final static byte[] decodeFast(byte[] sArr) { + // Check special case + int sLen = sArr.length; + if (sLen == 0) + return new byte[0]; + + int sIx = 0, eIx = sLen - 1; // Start and end index after trimming. + + // Trim illegal chars from start + while (sIx < eIx && IA[sArr[sIx] & 0xff] < 0) + sIx++; + + // Trim illegal chars from end + while (eIx > 0 && IA[sArr[eIx] & 0xff] < 0) + eIx--; + + // get the padding count (=) (0, 1 or 2) + int pad = sArr[eIx] == '=' ? (sArr[eIx - 1] == '=' ? 2 : 1) : 0; // Count + // '=' + // at + // end. + int cCnt = eIx - sIx + 1; // Content count including possible separators + int sepCnt = sLen > 76 ? (sArr[76] == '\r' ? cCnt / 78 : 0) << 1 : 0; + + int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded + // bytes + byte[] dArr = new byte[len]; // Preallocate byte[] of exact length + + // Decode all but the last 0 - 2 bytes. + int d = 0; + for (int cc = 0, eLen = (len / 3) * 3; d < eLen;) { + // Assemble three bytes into an int from four "valid" characters. + int i = IA[sArr[sIx++]] << 18 | IA[sArr[sIx++]] << 12 | IA[sArr[sIx++]] << 6 | IA[sArr[sIx++]]; + + // Add the bytes + dArr[d++] = (byte) (i >> 16); + dArr[d++] = (byte) (i >> 8); + dArr[d++] = (byte) i; + + // If line separator, jump over it. + if (sepCnt > 0 && ++cc == 19) { + sIx += 2; + cc = 0; + } + } + + if (d < len) { + // Decode last 1-3 bytes (incl '=') into 1-3 bytes + int i = 0; + for (int j = 0; sIx <= eIx - pad; j++) + i |= IA[sArr[sIx++]] << (18 - j * 6); + + for (int r = 16; d < len; r -= 8) + dArr[d++] = (byte) (i >> r); + } + + return dArr; + } + + // **************************************************************************************** + // * String version + // **************************************************************************************** + + /** + * Encodes a raw byte array into a BASE64 String representation + * i accordance with RFC 2045. + * + * @param sArr + * The bytes to convert. If null or length 0 an + * empty array will be returned. + * @param lineSep + * Optional "\r\n" after 76 characters, unless end of file.
+ * No line separator will be in breach of RFC 2045 which + * specifies max 76 per line but will be a little faster. + * @return A BASE64 encoded array. Never null. + */ + public final static String encodeToString(byte[] sArr, boolean lineSep) { + // Reuse char[] since we can't create a String incrementally anyway and + // StringBuffer/Builder would be slower. + return new String(encodeToChar(sArr, lineSep)); + } + + /** + * Decodes a BASE64 encoded String. All illegal characters will + * be ignored and can handle both strings with and without line separators. + *
+ * Note! It can be up to about 2x the speed to call + * decode(str.toCharArray()) instead. That will create a + * temporary array though. This version will use str.charAt(i) + * to iterate the string. + * + * @param str + * The source string. null or length 0 will return + * an empty array. + * @return The decoded array of bytes. May be of length 0. Will be + * null if the legal characters (including '=') isn't + * divideable by 4. (I.e. definitely corrupted). + */ + public final static byte[] decode(String str) { + // Check special case + int sLen = str != null ? str.length() : 0; + if (sLen == 0) + return new byte[0]; + + // Count illegal characters (including '\r', '\n') to know what size the + // returned array will be, + // so we don't have to reallocate & copy it later. + int sepCnt = 0; // Number of separator characters. (Actually illegal + // characters, but that's a bonus...) + for (int i = 0; i < sLen; i++) + // If input is "pure" (I.e. no line separators or illegal chars) + // base64 this loop can be commented out. + if (IA[str.charAt(i)] < 0) + sepCnt++; + + // Check so that legal chars (including '=') are evenly divideable by 4 + // as specified in RFC 2045. + if ((sLen - sepCnt) % 4 != 0) + return null; + + // Count '=' at end + int pad = 0; + for (int i = sLen; i > 1 && IA[str.charAt(--i)] <= 0;) + if (str.charAt(i) == '=') + pad++; + + int len = ((sLen - sepCnt) * 6 >> 3) - pad; + + byte[] dArr = new byte[len]; // Preallocate byte[] of exact length + + for (int s = 0, d = 0; d < len;) { + // Assemble three bytes into an int from four "valid" characters. + int i = 0; + for (int j = 0; j < 4; j++) { // j only increased if a valid char + // was found. + int c = IA[str.charAt(s++)]; + if (c >= 0) + i |= c << (18 - j * 6); + else + j--; + } + // Add the bytes + dArr[d++] = (byte) (i >> 16); + if (d < len) { + dArr[d++] = (byte) (i >> 8); + if (d < len) + dArr[d++] = (byte) i; + } + } + return dArr; + } + + /** + * Decodes a BASE64 encoded string that is known to be resonably well + * formatted. The method is about twice as fast as {@link #decode(String)}. + * The preconditions are:
+ * + The array must have a line length of 76 chars OR no line separators at + * all (one line).
+ * + Line separator must be "\r\n", as specified in RFC 2045 + The array + * must not contain illegal characters within the encoded string
+ * + The array CAN have illegal characters at the beginning and end, those + * will be dealt with appropriately.
+ * + * @param s + * The source string. Length 0 will return an empty array. + * null will throw an exception. + * @return The decoded array of bytes. May be of length 0. + */ + public final static byte[] decodeFast(String s) { + // Check special case + int sLen = s.length(); + if (sLen == 0) + return new byte[0]; + + int sIx = 0, eIx = sLen - 1; // Start and end index after trimming. + + // Trim illegal chars from start + while (sIx < eIx && IA[s.charAt(sIx) & 0xff] < 0) + sIx++; + + // Trim illegal chars from end + while (eIx > 0 && IA[s.charAt(eIx) & 0xff] < 0) + eIx--; + + // get the padding count (=) (0, 1 or 2) + int pad = s.charAt(eIx) == '=' ? (s.charAt(eIx - 1) == '=' ? 2 : 1) : 0; // Count + // '=' + // at + // end. + int cCnt = eIx - sIx + 1; // Content count including possible separators + int sepCnt = sLen > 76 ? (s.charAt(76) == '\r' ? cCnt / 78 : 0) << 1 : 0; + + int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded + // bytes + byte[] dArr = new byte[len]; // Preallocate byte[] of exact length + + // Decode all but the last 0 - 2 bytes. + int d = 0; + for (int cc = 0, eLen = (len / 3) * 3; d < eLen;) { + // Assemble three bytes into an int from four "valid" characters. + int i = IA[s.charAt(sIx++)] << 18 | IA[s.charAt(sIx++)] << 12 | IA[s.charAt(sIx++)] << 6 | IA[s.charAt(sIx++)]; + + // Add the bytes + dArr[d++] = (byte) (i >> 16); + dArr[d++] = (byte) (i >> 8); + dArr[d++] = (byte) i; + + // If line separator, jump over it. + if (sepCnt > 0 && ++cc == 19) { + sIx += 2; + cc = 0; + } + } + + if (d < len) { + // Decode last 1-3 bytes (incl '=') into 1-3 bytes + int i = 0; + for (int j = 0; sIx <= eIx - pad; j++) + i |= IA[s.charAt(sIx++)] << (18 - j * 6); + + for (int r = 16; d < len; r -= 8) + dArr[d++] = (byte) (i >> r); + } + + return dArr; + } +} diff --git a/src/main/java/osc/git/eh3/utils/GeoHash.java b/src/main/java/osc/git/eh3/utils/GeoHash.java index 428ebbf..59a2aff 100644 --- a/src/main/java/osc/git/eh3/utils/GeoHash.java +++ b/src/main/java/osc/git/eh3/utils/GeoHash.java @@ -3,6 +3,7 @@ package osc.git.eh3.utils; import java.util.BitSet; import java.util.HashMap; + /** * GeoHash算法实现 * @@ -54,8 +55,10 @@ public class GeoHash { latset.set(j++, isSet); } // 中国地理坐标:东经73°至东经135°,北纬4°至北纬53° - double lon = decode(lonset, 70, 140); - double lat = decode(latset, 0, 60); +// double lon = decode(lonset, 70, 140); +// double lat = decode(latset, 0, 60); + double lon = decode(lonset, -180, 180); + double lat = decode(latset, -90, 90); return new double[] { lat, lon }; } @@ -73,8 +76,10 @@ public class GeoHash { } public static String encode(double lat, double lon) { - BitSet latbits = getBits(lat, 0, 60); - BitSet lonbits = getBits(lon, 70, 140); +// BitSet latbits = getBits(lat, 0, 60); +// BitSet lonbits = getBits(lon, 70, 140); + BitSet latbits = getBits(lat, -90, 90); + BitSet lonbits = getBits(lon, -180, 180); StringBuilder buffer = new StringBuilder(); for (int i = 0; i < numbits; i++) { buffer.append((lonbits.get(i)) ? '1' : '0'); diff --git a/src/main/java/osc/git/eh3/utils/GeoHash2.java b/src/main/java/osc/git/eh3/utils/GeoHash2.java new file mode 100644 index 0000000..9c50496 --- /dev/null +++ b/src/main/java/osc/git/eh3/utils/GeoHash2.java @@ -0,0 +1,116 @@ +package osc.git.eh3.utils; + +import java.util.BitSet; +import java.util.HashMap; + +public class GeoHash2 { + + private static int numbits = 6 * 5; + final static char[] digits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm', 'n', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; + + final static HashMap lookup = new HashMap(); + + static { + int i = 0; + for (char c : digits) + lookup.put(c, i++); + } + + public static void main(String[] args) throws Exception { + + double lon1 = 109.014520; + double lat1 = 34.236080; + System.out.println(new GeoHash2().encode(lat1, lon1)); + + } + + public double[] decode(String geohash) { + StringBuilder buffer = new StringBuilder(); + for (char c : geohash.toCharArray()) { + + int i = lookup.get(c) + 32; + buffer.append(Integer.toString(i, 2).substring(1)); + } + + BitSet lonset = new BitSet(); + BitSet latset = new BitSet(); + + // even bits + int j = 0; + for (int i = 0; i < numbits * 2; i += 2) { + boolean isSet = false; + if (i < buffer.length()) + isSet = buffer.charAt(i) == '1'; + lonset.set(j++, isSet); + } + + // odd bits + j = 0; + for (int i = 1; i < numbits * 2; i += 2) { + boolean isSet = false; + if (i < buffer.length()) + isSet = buffer.charAt(i) == '1'; + latset.set(j++, isSet); + } + + double lon = decode(lonset, -180, 180); + double lat = decode(latset, -90, 90); + + return new double[] { lat, lon }; + } + + private double decode(BitSet bs, double floor, double ceiling) { + double mid = 0; + for (int i = 0; i < bs.length(); i++) { + mid = (floor + ceiling) / 2; + if (bs.get(i)) + floor = mid; + else + ceiling = mid; + } + return mid; + } + + public String encode(double lat, double lon) { + BitSet latbits = getBits(lat, -90, 90); + BitSet lonbits = getBits(lon, -180, 180); + StringBuilder buffer = new StringBuilder(); + for (int i = 0; i < numbits; i++) { + buffer.append((lonbits.get(i)) ? '1' : '0'); + buffer.append((latbits.get(i)) ? '1' : '0'); + } + return base32(Long.parseLong(buffer.toString(), 2)); + } + + private BitSet getBits(double lat, double floor, double ceiling) { + BitSet buffer = new BitSet(numbits); + for (int i = 0; i < numbits; i++) { + double mid = (floor + ceiling) / 2; + if (lat >= mid) { + buffer.set(i); + floor = mid; + } else { + ceiling = mid; + } + } + return buffer; + } + + public static String base32(long i) { + char[] buf = new char[65]; + int charPos = 64; + boolean negative = (i < 0); + if (!negative) + i = -i; + while (i <= -32) { + buf[charPos--] = digits[(int) (-(i % 32))]; + i /= 32; + } + buf[charPos] = digits[(int) (-i)]; + + if (negative) + buf[--charPos] = '-'; + return new String(buf, charPos, (65 - charPos)); + } +} \ No newline at end of file diff --git a/src/main/java/osc/git/eh3/utils/HttpClientUtil.java b/src/main/java/osc/git/eh3/utils/HttpClientUtil.java new file mode 100644 index 0000000..6467d07 --- /dev/null +++ b/src/main/java/osc/git/eh3/utils/HttpClientUtil.java @@ -0,0 +1,316 @@ +package osc.git.eh3.utils; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.http.HttpEntity; +import org.apache.http.HttpStatus; +import org.apache.http.NameValuePair; +import org.apache.http.client.config.CookieSpecs; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.config.Registry; +import org.apache.http.config.RegistryBuilder; +import org.apache.http.cookie.Cookie; +import org.apache.http.cookie.CookieOrigin; +import org.apache.http.cookie.CookieSpec; +import org.apache.http.cookie.CookieSpecProvider; +import org.apache.http.cookie.MalformedCookieException; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.BasicCookieStore; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.cookie.BestMatchSpecFactory; +import org.apache.http.impl.cookie.BrowserCompatSpec; +import org.apache.http.impl.cookie.BrowserCompatSpecFactory; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.protocol.HttpContext; + +@SuppressWarnings("deprecation") +public class HttpClientUtil { + private static Log log = LogFactory.getLog(HttpClientUtil.class); + private static final int timeOut = 30000;// timeOut(Millisecond) + private static final int BUFFERSIZE = 2048; + + private static Registry getRegistry() { + return RegistryBuilder. create().register(CookieSpecs.BEST_MATCH, new BestMatchSpecFactory()) + .register(CookieSpecs.BROWSER_COMPATIBILITY, new BrowserCompatSpecFactory()).register("easy", getCookieProvider()).build(); + } + + private static CookieSpecProvider getCookieProvider() { + return new CookieSpecProvider() { + public CookieSpec create(HttpContext arg0) { + // TODO Auto-generated method stub + return new BrowserCompatSpec() { + @Override + public void validate(Cookie cookie, CookieOrigin origin) throws MalformedCookieException { + // Oh, I am easy + } + }; + } + }; + } + + public static String sendPostParamDefaultCookie(String url, Map postParam) throws Exception { + String result = null; + StringBuffer out = null; + CloseableHttpClient httpclient = null; + HttpPost postmethod = null; + RequestConfig requestConfig = null; + HttpEntity entity = null; + CloseableHttpResponse response = null; + BasicCookieStore cookieStore = null; + Registry r = null; + List nvps = null; + BufferedReader br = null; + InputStreamReader isr = null; + InputStream inputStream = null; + try { + out = new StringBuffer();// 返回数据 + cookieStore = new BasicCookieStore(); + r = getRegistry(); + postmethod = new HttpPost(url); + requestConfig = RequestConfig.custom().setCookieSpec("easy").setConnectionRequestTimeout(timeOut).setConnectTimeout(timeOut) + .setSocketTimeout(timeOut).build(); + httpclient = HttpClients.custom().setDefaultCookieSpecRegistry(r).setDefaultRequestConfig(requestConfig) + .setDefaultCookieStore(cookieStore).build(); + nvps = new ArrayList(); + if (postParam != null && postParam.size() != 0) { + for (String param : postParam.keySet()) { + nvps.add(new BasicNameValuePair(param, postParam.get(param))); + } + } + postmethod.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8")); + response = httpclient.execute(postmethod); + int statusCode = response.getStatusLine().getStatusCode(); + if (statusCode == HttpStatus.SC_OK) { + entity = response.getEntity(); + inputStream = entity.getContent(); + isr = new InputStreamReader(inputStream, "UTF-8"); + br = new BufferedReader(isr); + int count = 0; + char[] b = new char[BUFFERSIZE]; + while ((count = br.read(b, 0, BUFFERSIZE)) != -1) { + out.append(new String(b, 0, count)); + } + } else { + out.append(SystemConstants.SYSTEM_ERROR); + } + } catch (Exception e) { + out.append(SystemConstants.SYSTEM_ERROR); + } finally { + if (br != null) { + br.close(); + } + if (isr != null) { + isr.close(); + } + if (inputStream != null) { + inputStream.close(); + } + if (response != null) { + response.close(); + } + if (postmethod != null) { + postmethod.releaseConnection(); + } + if (httpclient != null) { + httpclient.close(); + } + result = out.toString(); + out.setLength(0); + out = null; + } + return result; + } + + public static String sendPostParam(String url, Map postParam) throws Exception { + log.debug("请求地址:" + url); + String result = null; + StringBuffer out = null; + CloseableHttpClient httpclient = null; + HttpPost postmethod = null; + RequestConfig requestConfig = null; + HttpEntity entity = null; + CloseableHttpResponse response = null; + List nvps = null; + BufferedReader br = null; + InputStreamReader isr = null; + InputStream inputStream = null; + try { + out = new StringBuffer();// 返回数据 + httpclient = HttpClients.createDefault(); + postmethod = new HttpPost(url); + requestConfig = RequestConfig.custom().setConnectionRequestTimeout(timeOut).setConnectTimeout(timeOut).setSocketTimeout(timeOut) + .build(); + postmethod.setConfig(requestConfig); + nvps = new ArrayList(); + if (postParam != null && postParam.size() != 0) { + for (String param : postParam.keySet()) { + nvps.add(new BasicNameValuePair(param, postParam.get(param))); + } + } + postmethod.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8")); + response = httpclient.execute(postmethod); + int statusCode = response.getStatusLine().getStatusCode(); + if (statusCode == HttpStatus.SC_OK) { + entity = response.getEntity(); + inputStream = entity.getContent(); + isr = new InputStreamReader(inputStream, "UTF-8"); + br = new BufferedReader(isr); + int count = 0; + char[] b = new char[BUFFERSIZE]; + while ((count = br.read(b, 0, BUFFERSIZE)) != -1) { + out.append(new String(b, 0, count)); + } + } else { + out.append(SystemConstants.SYSTEM_ERROR); + } + } catch (Exception e) { + out.append(SystemConstants.SYSTEM_ERROR); + } finally { + if (br != null) { + br.close(); + } + if (isr != null) { + isr.close(); + } + if (inputStream != null) { + inputStream.close(); + } + if (response != null) { + response.close(); + } + if (postmethod != null) { + postmethod.releaseConnection(); + } + if (httpclient != null) { + httpclient.close(); + } + result = out.toString(); + out.setLength(0); + out = null; + } + return result; + } + + public static String sendPostJSONData(String url, String json) throws Exception { + log.debug("请求地址:" + url); + String result = null; + StringBuffer out = null; + CloseableHttpClient httpclient = null; + HttpPost postmethod = null; + RequestConfig requestConfig = null; + HttpEntity entity = null; + StringEntity strentity = null; + CloseableHttpResponse response = null; + BufferedReader br = null; + InputStreamReader isr = null; + InputStream inputStream = null; + try { + out = new StringBuffer();// 返回数据 + httpclient = HttpClients.createDefault(); + postmethod = new HttpPost(url); + requestConfig = RequestConfig.custom().setConnectionRequestTimeout(timeOut).setConnectTimeout(timeOut).setSocketTimeout(timeOut) + .build(); + postmethod.setConfig(requestConfig); + strentity = new StringEntity(URLEncoder.encode(json.toString(), "UTF-8")); + postmethod.addHeader("content-type", "application/json"); + postmethod.setEntity(strentity); + response = httpclient.execute(postmethod); + int statusCode = response.getStatusLine().getStatusCode(); + if (statusCode == HttpStatus.SC_OK) { + entity = response.getEntity(); + inputStream = entity.getContent(); + isr = new InputStreamReader(inputStream, "UTF-8"); + br = new BufferedReader(isr); + int count = 0; + char[] b = new char[BUFFERSIZE]; + while ((count = br.read(b, 0, BUFFERSIZE)) != -1) { + out.append(new String(b, 0, count)); + } + } else { + out.append(SystemConstants.SYSTEM_ERROR); + } + } catch (Exception e) { + out.append(SystemConstants.SYSTEM_ERROR); + } finally { + if (br != null) { + br.close(); + } + if (isr != null) { + isr.close(); + } + if (inputStream != null) { + inputStream.close(); + } + if (response != null) { + response.close(); + } + if (postmethod != null) { + postmethod.releaseConnection(); + } + if (httpclient != null) { + httpclient.close(); + } + result = out.toString(); + out.setLength(0); + out = null; + } + return result; + } + + /** + * 向指定URL发送GET方法的请求 + * + * @param url + * 发送请求的URL + * @return URL 所代表远程资源的响应结果 + */ + public static String sendGet(String url) { + String result = ""; + BufferedReader in = null; + try { + URL realUrl = new URL(url); + // 打开和URL之间的连接 + URLConnection connection = realUrl.openConnection(); + // 设置通用的请求属性 + connection.setRequestProperty("accept", "*/*"); + connection.setRequestProperty("connection", "Keep-Alive"); + connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); + // 建立实际的连接 + connection.connect(); + // 定义 BufferedReader输入流来读取URL的响应 + in = new BufferedReader(new InputStreamReader(connection.getInputStream())); + String line; + while ((line = in.readLine()) != null) { + result += line; + } + } catch (Exception e) { + System.out.println("发送GET请求出现异常!" + e); + e.printStackTrace(); + } + // 使用finally块来关闭输入流 + finally { + try { + if (in != null) { + in.close(); + } + } catch (Exception e2) { + e2.printStackTrace(); + } + } + return result; + } +} diff --git a/src/main/java/osc/git/eh3/utils/MD5.java b/src/main/java/osc/git/eh3/utils/MD5.java new file mode 100644 index 0000000..77da26b --- /dev/null +++ b/src/main/java/osc/git/eh3/utils/MD5.java @@ -0,0 +1,42 @@ +package osc.git.eh3.utils; + +import java.io.UnsupportedEncodingException; + +import org.apache.commons.codec.digest.DigestUtils; + +public class MD5 { + + public static String sign(String text, String key) { + return sign(text, key, "UTF-8"); + } + + public static String sign(String text, String key, String input_charset) { + text = text + key; + return DigestUtils.md5Hex(getContentBytes(text, input_charset)); + } + + public static boolean verify(String text, String sign, String key) { + return verify(text, sign, key, "UTF-8"); + } + + public static boolean verify(String text, String sign, String key, String input_charset) { + text = text + key; + String mysign = DigestUtils.md5Hex(getContentBytes(text, input_charset)); + if (mysign.equals(sign)) { + return true; + } else { + return false; + } + } + + private static byte[] getContentBytes(String content, String charset) { + if (charset == null || "".equals(charset)) { + return content.getBytes(); + } + try { + return content.getBytes(charset); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException("MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset); + } + } +} diff --git a/src/main/java/osc/git/eh3/utils/SystemConstants.java b/src/main/java/osc/git/eh3/utils/SystemConstants.java new file mode 100644 index 0000000..a0bfe59 --- /dev/null +++ b/src/main/java/osc/git/eh3/utils/SystemConstants.java @@ -0,0 +1,15 @@ +package osc.git.eh3.utils; + +public class SystemConstants { + public final static String RES_CODE = "rescode"; + + public final static String RES_DES = "resdes"; + + public final static String SYSTEM_ERROR = "201"; + + public final static String SYSTEM_SUCCESS = "200"; + + public final static String SYSTEM_SUCCESS_HEART = "203"; + + public final static String SYSTEM_ERROR_CANOT_CALL_INSURE = "206"; +}