reactive
parent
8572148c15
commit
6673306bb8
|
@ -15,7 +15,7 @@
|
|||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
|
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_10">
|
||||
<output url="file://$MODULE_DIR$/target/classes" />
|
||||
<output-test url="file://$MODULE_DIR$/target/test-classes" />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
|
@ -105,5 +105,7 @@
|
|||
<orderEntry type="library" name="Maven: com.google.errorprone:error_prone_annotations:2.0.18" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.google.j2objc:j2objc-annotations:1.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.codehaus.mojo:animal-sniffer-annotations:1.14" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.jodd:jodd-props:3.6.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.jodd:jodd-core:3.6.1" level="project" />
|
||||
</component>
|
||||
</module>
|
5
pom.xml
5
pom.xml
|
@ -258,6 +258,11 @@
|
|||
<artifactId>guava</artifactId>
|
||||
<version>22.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jodd</groupId>
|
||||
<artifactId>jodd-props</artifactId>
|
||||
<version>3.6.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<finalName>java-utils</finalName>
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -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] + " ");
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -26,9 +26,11 @@ public class HelloRxJava {
|
|||
|
||||
@Override
|
||||
public void onNext(String strings) {
|
||||
System.out.println("same hello " + strings);
|
||||
System.out.println("say hello " + strings);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Observable.from(names).subscribe(name -> System.out.println("say hello " + name), Throwable::printStackTrace, () -> System.out.println("Completed!"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,29 +19,42 @@ public class TestRx {
|
|||
|
||||
// Tasks oa -> oc, both in the same thread 1.
|
||||
Observable<String> 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<String> 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<String> 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<String> 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<String> 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<String> 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");
|
||||
|
|
|
@ -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<Integer>) 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<Integer>() {
|
||||
@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<Integer> 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
package me.ehlxr.token;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.util.Date;
|
||||
|
||||
public class TokenCommonUtil {
|
||||
|
||||
//使用ThreadLocal变量,防止线程冲突
|
||||
private static ThreadLocal<MessageDigest> mdThreadLocal = new ThreadLocal<MessageDigest>();
|
||||
|
||||
|
||||
/**
|
||||
* 计算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;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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<String, Integer> 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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<String, TokenVersionConfig> 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
Loading…
Reference in New Issue