diff --git a/java-utils.iml b/java-utils.iml index 482b5bc..c94a0f6 100644 --- a/java-utils.iml +++ b/java-utils.iml @@ -15,7 +15,7 @@ - + @@ -105,5 +105,7 @@ + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index d71fe49..afb08a2 100644 --- a/pom.xml +++ b/pom.xml @@ -258,6 +258,11 @@ guava 22.0 + + org.jodd + jodd-props + 3.6.1 + java-utils diff --git a/resources/idea/go-settings.jar b/resources/idea/go-settings.jar index 3332472..1ac9ecc 100644 Binary files a/resources/idea/go-settings.jar and b/resources/idea/go-settings.jar differ diff --git a/resources/idea/mac-settings.jar b/resources/idea/mac-settings.jar index 349a750..d0e174f 100644 Binary files a/resources/idea/mac-settings.jar and b/resources/idea/mac-settings.jar differ diff --git a/src/main/java/me/ehlxr/PrintMatrixClockWisely.java b/src/main/java/me/ehlxr/PrintMatrixClockWisely.java new file mode 100644 index 0000000..cefbe36 --- /dev/null +++ b/src/main/java/me/ehlxr/PrintMatrixClockWisely.java @@ -0,0 +1,74 @@ +package me.ehlxr; + +/** + * Created by lixiangrong on 2018/2/13. + */ +public class PrintMatrixClockWisely { + /** + * 题目:输入一个矩阵,按照从外向里以顺时针的顺序打印出每一个数字。 + * 思路: + * 循环打印: + * 1:先打印一行(第 1 行肯定会打印) + * 2:再打印当前矩阵的最后一列 + * 3:再倒序打印当前矩阵的最后一行 + * 4:再倒序打印当前矩阵的第一列 + * 起始坐标的规律: + * (0,0),(1,1),(2,2)...(startX,startY), 起始坐标的两个坐标值相等。 + * 并且 startX<= (rows-1)/2,startY<=(columns-1)/2 + * 当前矩阵,第 1 行 坐标 (start,columns-1-start) => (start,endX) + * 当前矩阵,最后 1 列 坐标 (start+1,rows-1-start) => (start+1,endY) + * 当前矩阵,最后 1 行 坐标 (start,columns-1-start+1) => (start,endX-1) + * 当前矩阵,第 1 行 坐标 (start+1,columns-1+1) => (start+1,endY-1) + * + * @author WangSai + */ + public static void main(String[] args) { + // TODO Auto-generated method stub + // 初始化矩阵 arr[][] + int[][] arr = new int[5][5]; + for (int i = 0; i < arr.length; i++) { + for (int j = 0; j < arr[i].length; j++) { + arr[i][j] = i * arr[i].length + j; + System.out.print(arr[i][j] + " " + '\t'); + } + System.out.println(); + } + System.out.println("顺时针打印矩阵:"); + // 顺时针打印矩阵 arr[][] + printMatrixWisely(arr); + } + + // 循环打印 + private static void printMatrixWisely(int[][] arr) { + if (arr == null || arr.length < 1 || arr[0].length < 1) + return; + int start = 0; + int rows = arr.length; + int columns = arr[0].length; + while (2 * start < columns && 2 * start < rows) { + printMatrix(arr, rows, columns, start); + start++; + } + } + + // 打印一圈 + private static void printMatrix(int[][] arr, int rows, int columns, int start) { + int endX = columns - 1 - start; // 最后一列的列号 + int endY = rows - 1 - start; // 最后一行的行号 + // 打印该圈第一行 + for (int i = start; i <= endX; i++) + System.out.print(arr[start][i] + " "); + // 打印该圈最后一列 (至少是两行) + if (start < endY) + for (int i = start + 1; i <= endY; i++) + System.out.print(arr[i][endX] + " "); + // 打印该圈最后一行 (至少是两行两列) + if ((start < endX) && (start < endY)) + for (int i = endX - 1; i >= start; i--) + System.out.print(arr[endY][i] + " "); + // 打印该圈的第一列 (至少是三行两列) + if ((start < endX) && (start < endY - 1)) + for (int i = endY - 1; i >= start + 1; i--) + System.out.print(arr[i][start] + " "); + } +} diff --git a/src/main/java/me/ehlxr/dfd.java b/src/main/java/me/ehlxr/dfd.java index 470b66a..c8e1ad6 100644 --- a/src/main/java/me/ehlxr/dfd.java +++ b/src/main/java/me/ehlxr/dfd.java @@ -1,10 +1,16 @@ package me.ehlxr; +import com.google.common.collect.Maps; + /** * Created by lixiangrong on 2016/12/23. */ public class dfd { + public static void main(String[] args) { + var map = Maps.newHashMap(); + map.put("d",1); + System.out.println(map); } public void printCircle(int[][] matrix, int startX, int startY, int endX, int endY) { // only one column left diff --git a/src/main/java/me/ehlxr/reactive/HelloRxJava.java b/src/main/java/me/ehlxr/reactive/HelloRxJava.java index 5f5da84..ba5aede 100644 --- a/src/main/java/me/ehlxr/reactive/HelloRxJava.java +++ b/src/main/java/me/ehlxr/reactive/HelloRxJava.java @@ -13,22 +13,24 @@ public class HelloRxJava { } private static void hello(String... names) { - Observable.from(names).subscribe(new Subscriber() { - @Override - public void onCompleted() { - System.out.println("Completed!"); - } + Observable.from(names).subscribe(new Subscriber() { + @Override + public void onCompleted() { + System.out.println("Completed!"); + } - @Override - public void onError(Throwable throwable) { - throwable.printStackTrace(); - } + @Override + public void onError(Throwable throwable) { + throwable.printStackTrace(); + } - @Override - public void onNext(String strings) { - System.out.println("same hello " + strings); - } + @Override + public void onNext(String strings) { + System.out.println("say hello " + strings); + } - }); + }); + + // Observable.from(names).subscribe(name -> System.out.println("say hello " + name), Throwable::printStackTrace, () -> System.out.println("Completed!")); } } diff --git a/src/main/java/me/ehlxr/reactive/TestRx.java b/src/main/java/me/ehlxr/reactive/TestRx.java index 2e366a7..d88a994 100644 --- a/src/main/java/me/ehlxr/reactive/TestRx.java +++ b/src/main/java/me/ehlxr/reactive/TestRx.java @@ -19,29 +19,42 @@ public class TestRx { // Tasks oa -> oc, both in the same thread 1. Observable oa = Observable.just("oa").observeOn(Schedulers.io()).flatMap( - soa -> Observable.fromCallable(new TimeConsumingService("fa", 1000, new String[]{})) + soa -> { + System.out.println("oa Thread: " + Thread.currentThread().getName()); + return Observable.fromCallable(new TimeConsumingService("fa", 2000, new String[]{soa})); + } ); Observable oc = oa.flatMap( res -> { - System.out.println(res); - System.out.println("Executed At: " + (System.currentTimeMillis() - startTime) + "ms"); - return Observable.fromCallable( - new TimeConsumingService("fc", 2000, new String[]{res})); + System.out.println("oc Thread: " + Thread.currentThread().getName()); + // System.out.println(res); + // System.out.println("Executed At: " + (System.currentTimeMillis() - startTime) + "ms"); + return Observable.fromCallable(new TimeConsumingService("fc", 1000, new String[]{res})); }); // tasks ob -> (od,oe), ob, od, oe have special thread 2,3,4. Observable ob = Observable.just("ob").observeOn(Schedulers.io()).flatMap( - sob -> Observable.fromCallable(new TimeConsumingService("fb", 2000, new String[]{})) + sob -> { + System.out.println("ob Thread: " + Thread.currentThread().getName()); + return Observable.fromCallable(new TimeConsumingService("fb", 2000, new String[]{sob})); + } ); Observable od_oe = ob.flatMap( res -> { - System.out.println(res); - System.out.println("Executed At: " + (System.currentTimeMillis() - startTime) + "ms"); + System.out.println("od_oe Thread: " + Thread.currentThread().getName()); + // System.out.println(res); + // System.out.println("Executed At: " + (System.currentTimeMillis() - startTime) + "ms"); Observable od = Observable.just("od").observeOn(Schedulers.io()).flatMap( - sod -> Observable.fromCallable(new TimeConsumingService("fd", 1000, new String[]{res})) + sod -> { + System.out.println("od Thread: " + Thread.currentThread().getName()); + return Observable.fromCallable(new TimeConsumingService("fd", 1000, new String[]{sod})); + } ); Observable oe = Observable.just("oe").observeOn(Schedulers.io()).flatMap( - sod -> Observable.fromCallable(new TimeConsumingService("fe", 1000, new String[]{res})) + soe -> { + System.out.println("oe Thread: " + Thread.currentThread().getName()); + return Observable.fromCallable(new TimeConsumingService("fe", 1000, new String[]{soe})); + } ); return Observable.merge(od, oe); }); @@ -51,8 +64,9 @@ public class TestRx { // tasks join oc,(od_oe) and subscribe Observable.merge(oc, od_oe).toBlocking().subscribe( res -> { - System.out.println(res); - System.out.println("Executed At: " + (System.currentTimeMillis() - startTime) + "ms"); + System.out.println("ss Thread: " + Thread.currentThread().getName()); + // System.out.println(res); + // System.out.println("Executed At: " + (System.currentTimeMillis() - startTime) + "ms"); }); System.out.println("End executed: " + (System.currentTimeMillis() - startTime) + "ms"); diff --git a/src/main/java/me/ehlxr/reactive/TestRx01.java b/src/main/java/me/ehlxr/reactive/TestRx01.java index eb9defd..9ae61ac 100644 --- a/src/main/java/me/ehlxr/reactive/TestRx01.java +++ b/src/main/java/me/ehlxr/reactive/TestRx01.java @@ -2,22 +2,66 @@ package me.ehlxr.reactive; import rx.Observable; +import rx.Subscriber; + +import java.util.concurrent.CountDownLatch; /** * Created by lixiangrong on 2018/1/16. * 链式函数式处理 */ public class TestRx01 { - public static void main(String[] args) { - hello(1, 2, 3, 4, 5); + public static void main(String[] args) throws Exception { + // hello(1, 2, 3, 4, 5); + testRxJavaWithoutBlocking(10000); + + Observable.create((Observable.OnSubscribe) observer -> { + try { + if (!observer.isUnsubscribed()) { + for (int i = 1; i < 5; i++) { + observer.onNext(i); + } + observer.onCompleted(); + } + } catch (Exception e) { + observer.onError(e); + } + }).subscribe(new Subscriber() { + @Override + public void onNext(Integer item) { + System.out.println("Next: " + item); + } + + @Override + public void onError(Throwable error) { + System.err.println("Error: " + error.getMessage()); + } + + @Override + public void onCompleted() { + System.out.println("Sequence complete."); + } + }); } private static void hello(Integer... integers) { Observable workflow = Observable.from(integers) .filter(i -> (i < 10) && (i > 0)) - .map(i -> i * 2); - workflow.subscribe(i -> System.out.print(i + "! ")); - System.out.println(); + .map(i -> i * 2).reduce((x, y) -> x + y); workflow.subscribe(i -> System.out.print(i + "! ")); } + + private static void testRxJavaWithoutBlocking(int count) throws Exception { + CountDownLatch finishedLatch = new CountDownLatch(1); + long t = System.nanoTime(); + + Observable.range(0, count) + .map(i -> 200) + .subscribe(s -> { + }, Throwable::printStackTrace, finishedLatch::countDown); + + finishedLatch.await(); + t = (System.nanoTime() - t) / 1000000; //ms + System.out.println("RxJavaWithoutBlocking TPS: " + count * 1000 / t); + } } diff --git a/src/main/java/me/ehlxr/thread/ThreadPoolExecutorTest.java b/src/main/java/me/ehlxr/thread/ThreadPoolExecutorTest.java index 57bacab..2c208fc 100644 --- a/src/main/java/me/ehlxr/thread/ThreadPoolExecutorTest.java +++ b/src/main/java/me/ehlxr/thread/ThreadPoolExecutorTest.java @@ -19,7 +19,7 @@ public class ThreadPoolExecutorTest { cachedThreadPool.execute (new Runnable() { public void run() { //System.out.println(index); - System.out.println(Thread.currentThread().getName()); + System.out.println("Thread: "+Thread.currentThread().getName()); } }); } diff --git a/src/main/java/me/ehlxr/token/Base62.java b/src/main/java/me/ehlxr/token/Base62.java new file mode 100644 index 0000000..cb1cc17 --- /dev/null +++ b/src/main/java/me/ehlxr/token/Base62.java @@ -0,0 +1,69 @@ +package me.ehlxr.token; + + +import java.io.ByteArrayOutputStream; + +/** + * BASE62编码类 + */ +public class Base62 { + + private static char[] encodes = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + .toCharArray(); + private static byte[] decodes = new byte[256]; + + static { + for (int i = 0; i < encodes.length; i++) { + decodes[encodes[i]] = (byte) i; + } + } + + public static StringBuffer encodeBase62(byte[] data) { + StringBuffer sb = new StringBuffer(data.length * 2); + int pos = 0, val = 0; + for (int i = 0; i < data.length; i++) { + val = (val << 8) | (data[i] & 0xFF); + pos += 8; + while (pos > 5) { + char c = encodes[val >> (pos -= 6)]; + sb.append( + /**/c == 'i' ? "ia" : + /**/c == '+' ? "ib" : + /**/c == '/' ? "ic" : String.valueOf(c)); + val &= ((1 << pos) - 1); + } + } + if (pos > 0) { + char c = encodes[val << (6 - pos)]; + sb.append( + /**/c == 'i' ? "ia" : + /**/c == '+' ? "ib" : + /**/c == '/' ? "ic" : String.valueOf(c)); + } + return sb; + } + + public static byte[] decodeBase62(char[] data) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(data.length); + int pos = 0, val = 0; + for (int i = 0; i < data.length; i++) { + char c = data[i]; + if (c == 'i') { + c = data[++i]; + c = + /**/c == 'a' ? 'i' : + /**/c == 'b' ? '+' : + /**/c == 'c' ? '/' : data[--i]; + } + val = (val << 6) | decodes[c]; + pos += 6; + while (pos > 7) { + baos.write(val >> (pos -= 8)); + val &= ((1 << pos) - 1); + } + } + return baos.toByteArray(); + } + + +} diff --git a/src/main/java/me/ehlxr/token/TokenCommonUtil.java b/src/main/java/me/ehlxr/token/TokenCommonUtil.java new file mode 100644 index 0000000..5ebe3f7 --- /dev/null +++ b/src/main/java/me/ehlxr/token/TokenCommonUtil.java @@ -0,0 +1,132 @@ +package me.ehlxr.token; + +import java.security.MessageDigest; +import java.util.Date; + +public class TokenCommonUtil { + + //使用ThreadLocal变量,防止线程冲突 + private static ThreadLocal mdThreadLocal = new ThreadLocal(); + + + /** + * 计算MD5 + * + * @param bytes + * @return + */ + public static byte[] calculateMD5(byte[] bytes) { + byte b[]; + MessageDigest md = getMD(); + md.reset(); + md.update(bytes); + return md.digest(); + } + + private static MessageDigest getMD() { + MessageDigest md = mdThreadLocal.get(); + if (md == null) { + try { + md = MessageDigest.getInstance("MD5"); + mdThreadLocal.set(md); + } catch (Exception e) { + e.printStackTrace(); + } + } + return md; + } + + /** + * 将两个byte数组结合为一个bytes数组 + * + * @param byte_1 + * @param byte_2 + * @return + */ + public static byte[] byteMerger(byte[] byte_1, byte[] byte_2) { + byte[] byte_3 = new byte[byte_1.length + byte_2.length]; + System.arraycopy(byte_1, 0, byte_3, 0, byte_1.length); + System.arraycopy(byte_2, 0, byte_3, byte_1.length, byte_2.length); + return byte_3; + } + + /** + * 将int转为bytes + * + * @param byteNum + * @return + */ + public static int bytes2Int(byte[] byteNum) { + int num = 0; + for (int ix = 0; ix < 4; ++ix) { + num <<= 8; + num |= (byteNum[ix] & 0xff); + } + return num; + } + + /** + * 将bytes转为int + * + * @param num + * @return + */ + public static byte[] int2Bytes(int num) { + byte[] byteNum = new byte[4]; + for (int ix = 0; ix < 4; ++ix) { + int offset = 32 - (ix + 1) * 8; + byteNum[ix] = (byte) ((num >> offset) & 0xff); + } + return byteNum; + } + + /** + * 使用32位来表示时间,可以精确到秒 + * + * @return + */ + public static int getSecondTime() { + long timeLong = System.currentTimeMillis(); + Long timeInt = timeLong / 1000; + return timeInt.intValue(); + } + + /** + * 时间转化为日期 + * + * @param time + * @return + */ + public static Date secondTimeToDate(int time) { + long timeStamp = time * 1000l; + Date date = new Date(); + date.setTime(timeStamp); + return date; + } + + public static byte[] long2Bytes(long value) { + int binaryLength = getBytesLength(value); + long temp = value; + byte b[] = new byte[binaryLength]; + for (int i = binaryLength - 1; i > -1; i--) { + b[i] = new Long(temp & 0xff).byteValue(); + temp = temp >> 8; + } + return b; + } + + private static int getBytesLength(Long value) { + return Long.toBinaryString(value).length() % 8 == 0 ? Long.toBinaryString(value).length() / 8 : Long.toBinaryString(value).length() / 8 + 1; + } + + public static long bytes2long(byte[] b, int length) { + int num = 0; + for (int ix = 0; ix < length; ++ix) { + num <<= 8; + num |= (b[ix] & 0xff); + } + return num; + } + + +} diff --git a/src/main/java/me/ehlxr/token/TokenServerUtil.java b/src/main/java/me/ehlxr/token/TokenServerUtil.java new file mode 100644 index 0000000..f23a2e2 --- /dev/null +++ b/src/main/java/me/ehlxr/token/TokenServerUtil.java @@ -0,0 +1,173 @@ +package me.ehlxr.token; + + + +import java.io.IOException; + +/** + * Created by lixiangrong on 2018/2/2. + */ +public class TokenServerUtil { + + + + public static void main(String[] args) throws Exception { + Long uid = 178934567l; + // System.out.println(Long.toBinaryString(uid)); + // System.out.println(Long.toBinaryString(uid).length() % 8 == 0 ? Long.toBinaryString(uid).length() / 8 : Long.toBinaryString(uid).length() / 8 + 1); + //// long ct1 = System.currentTimeMillis() / 1000;//用秒来表示 + //// System.out.println("当前系统时间戳为:" + ct1); + String token1 = generatorToken(uid, TokenVersionEnum.VERSION_2.getValue()); + System.out.println("生成的token1为:" + token1 + "\n长度1为:" + token1.length()); + // + //// long ct2 = System.currentTimeMillis() / 1000;//用秒来表示 + //// System.out.println("当前系统时间戳为:" + ct2); + // String token2 = generatorToken(uid, TokenVersionEnum.VERSION_2.getValue()); + // System.out.println("生成的token2为:" + token2 + "\n长度2为:" + token2.length()); + // String wrongToken = "AVok"; + // String rightToken = "AVRibaN9MFUo9rOc9ocjXqqw"; + // byte[] rBytes = TokenCommonUtil.calculateMD5(rightToken.getBytes()); + // byte[] wBytes = TokenCommonUtil.calculateMD5(wrongToken.getBytes()); + // byte[] a = Base62.decodeBase62(rightToken.toCharArray()); + // byte[] b = Base62.decodeBase62(wrongToken.toCharArray()); + // System.out.println("rightToken MD5:" + rBytes); + // System.out.println("wrongToken MD5:" + wBytes); + // boolean isTrue1 = checkToken(wrongToken); + // System.out.println("对比结果为:" + isTrue1); + // boolean isTrue2 = checkToken(rightToken); + // System.out.println("对比结果为:" + isTrue2); + // TokenInfo tokenInfo = checkToken(token1); + // if (tokenInfo != null) { + // boolean isOK = tokenInfo.isOK(); + // System.out.println("version 1:"); + // System.out.println(isOK); + // } + // TokenInfo tokenInfo1 = checkToken("AVU4uP10CD1XYIlrJgLubtM"); + // if (tokenInfo1 != null) { + // boolean isOK = tokenInfo1.isOK(); + // Long uidR = tokenInfo1.getUid(); + // System.out.println("version 2:"); + // System.out.println(isOK); + // System.out.println(uidR); + // } + } + + + /** + * 计算token + * token规则为: + * {8位版本}{32位时间戳}{64位随机字符串}{32位校验} + * {1字节版本}{4字节时间戳}{8字节随机字符串}{4字节校验} + * + * @param uid 用户的唯一标识 + * @param version token的版本号 + * @return + */ + public static String generatorToken(Long uid, int version) + throws IOException { + + //获取当前系统时间,以秒为单位 + int time = TokenCommonUtil.getSecondTime(); + + return generatorToken(uid, version, time); + + + } + + /** + * 计算token + * token规则为: + * {8位版本}{32位时间戳}{64位随机字符串}{32位校验} + * {1字节版本}{4字节时间戳}{8字节随机字符串}{4字节校验} + * + * @param uid 用户的唯一标识 + * @param version token的版本号 + * @return + */ + public static String generatorToken(Long uid, int version, int time) + throws IOException { + + //读取配置文件,通过版本号取得对应的token的加密解密的密钥,及自校验位的生成方式 + TokenVersionConfig tokenVersionConfig = TokenVersionFactory.getTokenConfig(version); + //生成token时用的密钥 + String create_token_key = tokenVersionConfig.getCreate_token_key(); + //生成自校验位时的密钥 + String check_token_key = tokenVersionConfig.getCheck_token_key(); + //分别取MD5加密后串的哪四个字节做为自校验位 + String check = tokenVersionConfig.getCheck(); + String[] checkArray = check.split(","); + int i1 = Integer.valueOf(checkArray[0]); + int i2 = Integer.valueOf(checkArray[1]); + int i3 = Integer.valueOf(checkArray[2]); + int i4 = Integer.valueOf(checkArray[3]); + // + // //获取当前系统时间,以秒为单位 + // int time = TokenCommonUtil.getSecondTime(); + + //计算{136位随机字符串,共17字节} + byte[] timeBytes = TokenCommonUtil.int2Bytes(time); + + byte[] udidHalfBytes = generate8MD5ByVersion(version, uid, create_token_key); + + //添加{1字节版本}{4字节时间戳} + byte vByte = (byte) version; + byte[] sidBytes = TokenCommonUtil.byteMerger(new byte[]{vByte}, timeBytes); + + //添加{1字节版本}{4字节时间戳}{中间8字节根据不同版本生成方法有变} + sidBytes = TokenCommonUtil.byteMerger(sidBytes, udidHalfBytes); + + //计算校验位 + byte[] sidMd5Bytes = TokenCommonUtil.byteMerger(sidBytes, check_token_key.getBytes()); + sidMd5Bytes = TokenCommonUtil.calculateMD5(sidMd5Bytes); + //根据配置文件中取相应版本对应的元素组成校验位 + byte[] sidCheckBytes = new byte[]{sidMd5Bytes[i1], sidMd5Bytes[i2], sidMd5Bytes[i3], sidMd5Bytes[i4]}; + + //添加校验位{1字节版本}{4字节时间戳}{中间8字节根据不同版本生成方法有变}{4字节校验} + sidBytes = TokenCommonUtil.byteMerger(sidBytes, sidCheckBytes); + //Base62编码 + String token = Base62.encodeBase62(sidBytes).toString(); + + return token; + } + + + /** + * 中间8字节根据不同版本号生成方式不同 + * + * @param version 当前生成token的版本号 + * @param uid 用户唯一标识 + * @param create_token_key token生成的密钥 + * @return 中间8字节 + */ + private static byte[] generate8MD5ByVersion(int version, Long uid, String create_token_key) { + if (version == TokenVersionEnum.VERSION_1.getValue()) { + String udidBuilder = uid + create_token_key + System.currentTimeMillis(); + byte[] udidBytes = TokenCommonUtil.calculateMD5(udidBuilder.toString().getBytes()); + byte[] udidHalfBytes = new byte[8]; + System.arraycopy(udidBytes, 0, udidHalfBytes, 0, udidHalfBytes.length); + return udidHalfBytes; + } else if (version == TokenVersionEnum.VERSION_2.getValue()) { + //{1字节的uid字节长度} + int binaryLength = getBytesLength(uid); + byte lengthBinary = (byte) binaryLength; + //{1字节的uid字节长度}{binaryLength字节的uid串} + byte[] uByte = TokenCommonUtil.long2Bytes(uid); + byte[] sidBytes = TokenCommonUtil.byteMerger(new byte[]{lengthBinary}, uByte); + //{7 - binaryLength字节MD5的串} + String udidBuilder = create_token_key + System.currentTimeMillis(); + byte[] udidBytes = TokenCommonUtil.calculateMD5(udidBuilder.toString().getBytes()); + + byte[] udidHalfBytes = new byte[7 - binaryLength]; + System.arraycopy(udidBytes, 0, udidHalfBytes, 0, udidHalfBytes.length); + //{1字节的uid字节长度}{binaryLength字节的uid串}{7 - binaryLength字节MD5的串} + sidBytes = TokenCommonUtil.byteMerger(sidBytes, udidHalfBytes); + return sidBytes; + } + return null; + } + + private static int getBytesLength(Long uid) { + return Long.toBinaryString(uid).length() % 8 == 0 ? Long.toBinaryString(uid).length() / 8 : Long.toBinaryString(uid).length() / 8 + 1; + } + +} diff --git a/src/main/java/me/ehlxr/token/TokenVersionConfig.java b/src/main/java/me/ehlxr/token/TokenVersionConfig.java new file mode 100644 index 0000000..2f720e2 --- /dev/null +++ b/src/main/java/me/ehlxr/token/TokenVersionConfig.java @@ -0,0 +1,47 @@ +package me.ehlxr.token; + +/** + * token版本相关的配置 + * User: erin + * Date: 14-10-30 + * Time: 下午5:34 + */ +public class TokenVersionConfig { + + private int version;//token的版本号 + private String create_token_key;//生成token的key + private String check_token_key;//自校验token的key + private String check;//获取自校验位时,取哪些元素 + + public int getVersion() { + return version; + } + + public void setVersion(int version) { + this.version = version; + } + + public String getCreate_token_key() { + return create_token_key; + } + + public void setCreate_token_key(String create_token_key) { + this.create_token_key = create_token_key; + } + + public String getCheck_token_key() { + return check_token_key; + } + + public void setCheck_token_key(String check_token_key) { + this.check_token_key = check_token_key; + } + + public String getCheck() { + return check; + } + + public void setCheck(String check) { + this.check = check; + } +} diff --git a/src/main/java/me/ehlxr/token/TokenVersionEnum.java b/src/main/java/me/ehlxr/token/TokenVersionEnum.java new file mode 100644 index 0000000..490178d --- /dev/null +++ b/src/main/java/me/ehlxr/token/TokenVersionEnum.java @@ -0,0 +1,40 @@ +package me.ehlxr.token; + +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; + +public enum TokenVersionEnum { + + VERSION_1(1), + VERSION_2(2); + + // provider数字与字符串映射字典表 + private static BiMap VERSION_MAPPING_DICT = HashBiMap.create(); + + static { + VERSION_MAPPING_DICT.put("1", VERSION_1.getValue()); + VERSION_MAPPING_DICT.put("2", VERSION_2.getValue()); + } + + private int value; + + TokenVersionEnum(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + + public static String getStringVersion(int version) { + return VERSION_MAPPING_DICT.inverse().get(version); + } + + public static boolean checkKeyIsExist(String version) { + if (VERSION_MAPPING_DICT.containsKey(version)) { + return true; + } + return false; + } + +} diff --git a/src/main/java/me/ehlxr/token/TokenVersionFactory.java b/src/main/java/me/ehlxr/token/TokenVersionFactory.java new file mode 100644 index 0000000..f1f68b0 --- /dev/null +++ b/src/main/java/me/ehlxr/token/TokenVersionFactory.java @@ -0,0 +1,63 @@ +package me.ehlxr.token; + + +import com.google.common.base.Strings; +import com.google.common.collect.Maps; +import jodd.props.Props; + +import java.io.IOException; +import java.io.InputStream; +import java.util.concurrent.ConcurrentMap; + +/** + * token版本控制工厂类 + * User: erin + * Date: 14-10-30 + * Time: 下午5:34 + */ +public class TokenVersionFactory { + + private static String TOKEN_VERSION = "tokenVersion"; + private static String RESOURCE_NAME = "token_version.properties"; + + private static Props properties = null; + + protected static ConcurrentMap versionMap = Maps.newConcurrentMap(); + + public static TokenVersionConfig getTokenConfig(int version) throws IOException { + + String versionString = TokenVersionEnum.getStringVersion(version); + TokenVersionConfig oAuthConsumer = versionMap.get(buildVersionKey(versionString)); + if (oAuthConsumer == null) { + oAuthConsumer = newResource(RESOURCE_NAME, versionString); + versionMap.putIfAbsent(buildVersionKey(versionString), oAuthConsumer); + } + return oAuthConsumer; + } + + private static synchronized TokenVersionConfig newResource(String resourceName, String versionStr) throws IOException { + properties = new Props(); + InputStream input = TokenVersionConfig.class.getClassLoader().getResourceAsStream(resourceName); + properties.load(input); + TokenVersionConfig tokenVersionConfig = new TokenVersionConfig(); + tokenVersionConfig.setVersion(Integer.valueOf(versionStr)); + tokenVersionConfig.setCheck_token_key(getValue("check_token_key", versionStr)); + tokenVersionConfig.setCreate_token_key(getValue("create_token_key", versionStr)); + tokenVersionConfig.setCheck(getValue("check", versionStr)); + return tokenVersionConfig; + } + + private static String getValue(String name, String provider) { + name = TOKEN_VERSION + "." + name; + String url = properties.getValue(name, provider); + if (Strings.isNullOrEmpty(url)) { + return null; + } + return url; + } + + private static String buildVersionKey(String versionStr) { + return versionStr + "_" + RESOURCE_NAME; + } + +} diff --git a/src/main/resources/token_version.properties b/src/main/resources/token_version.properties new file mode 100644 index 0000000..a74cd59 --- /dev/null +++ b/src/main/resources/token_version.properties @@ -0,0 +1,18 @@ +###author liuling +###token生成和校验相关配置 +[tokenVersion<1>] +###生成token时的密钥 +create_token_key=QJ=*S:y^s0$!@#&*()%xZ~&U8($*_+r? +###自校验时的密钥 +check_token_key=QJs#!@%er!#E#$%^%@@!@=**I()^%? +###取MD5加密后的哪几位做为自校验位,共计4字节,32位。最大数字不能超过16 +check=1,4,6,7 + + +[tokenVersion<2>] +###生成token时的密钥 +create_token_key=D#$%^@W#Rj8)@9o%&rgyYL_+!Ldcr5td +###自校验时的密钥 +check_token_key=TL9$_q+Yv^zR):f8)e@P@z&*1@)^o? +###取MD5加密后的哪几位做为自校验位,共计4字节,32位。最大数字不能超过16 +check=8,2,2,5 \ No newline at end of file