reactive
parent
8572148c15
commit
6673306bb8
|
@ -15,7 +15,7 @@
|
||||||
</configuration>
|
</configuration>
|
||||||
</facet>
|
</facet>
|
||||||
</component>
|
</component>
|
||||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
|
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_10">
|
||||||
<output url="file://$MODULE_DIR$/target/classes" />
|
<output url="file://$MODULE_DIR$/target/classes" />
|
||||||
<output-test url="file://$MODULE_DIR$/target/test-classes" />
|
<output-test url="file://$MODULE_DIR$/target/test-classes" />
|
||||||
<content url="file://$MODULE_DIR$">
|
<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.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: 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.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>
|
</component>
|
||||||
</module>
|
</module>
|
5
pom.xml
5
pom.xml
|
@ -258,6 +258,11 @@
|
||||||
<artifactId>guava</artifactId>
|
<artifactId>guava</artifactId>
|
||||||
<version>22.0</version>
|
<version>22.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jodd</groupId>
|
||||||
|
<artifactId>jodd-props</artifactId>
|
||||||
|
<version>3.6.1</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<build>
|
<build>
|
||||||
<finalName>java-utils</finalName>
|
<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;
|
package me.ehlxr;
|
||||||
|
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by lixiangrong on 2016/12/23.
|
* Created by lixiangrong on 2016/12/23.
|
||||||
*/
|
*/
|
||||||
public class dfd {
|
public class dfd {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
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) {
|
public void printCircle(int[][] matrix, int startX, int startY, int endX, int endY) {
|
||||||
// only one column left
|
// only one column left
|
||||||
|
|
|
@ -13,22 +13,24 @@ public class HelloRxJava {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void hello(String... names) {
|
private static void hello(String... names) {
|
||||||
Observable.from(names).subscribe(new Subscriber<String>() {
|
Observable.from(names).subscribe(new Subscriber<String>() {
|
||||||
@Override
|
@Override
|
||||||
public void onCompleted() {
|
public void onCompleted() {
|
||||||
System.out.println("Completed!");
|
System.out.println("Completed!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onError(Throwable throwable) {
|
public void onError(Throwable throwable) {
|
||||||
throwable.printStackTrace();
|
throwable.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNext(String strings) {
|
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.
|
// Tasks oa -> oc, both in the same thread 1.
|
||||||
Observable<String> oa = Observable.just("oa").observeOn(Schedulers.io()).flatMap(
|
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(
|
Observable<String> oc = oa.flatMap(
|
||||||
res -> {
|
res -> {
|
||||||
System.out.println(res);
|
System.out.println("oc Thread: " + Thread.currentThread().getName());
|
||||||
System.out.println("Executed At: " + (System.currentTimeMillis() - startTime) + "ms");
|
// System.out.println(res);
|
||||||
return Observable.fromCallable(
|
// System.out.println("Executed At: " + (System.currentTimeMillis() - startTime) + "ms");
|
||||||
new TimeConsumingService("fc", 2000, new String[]{res}));
|
return Observable.fromCallable(new TimeConsumingService("fc", 1000, new String[]{res}));
|
||||||
});
|
});
|
||||||
|
|
||||||
// tasks ob -> (od,oe), ob, od, oe have special thread 2,3,4.
|
// tasks ob -> (od,oe), ob, od, oe have special thread 2,3,4.
|
||||||
Observable<String> ob = Observable.just("ob").observeOn(Schedulers.io()).flatMap(
|
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(
|
Observable<String> od_oe = ob.flatMap(
|
||||||
res -> {
|
res -> {
|
||||||
System.out.println(res);
|
System.out.println("od_oe Thread: " + Thread.currentThread().getName());
|
||||||
System.out.println("Executed At: " + (System.currentTimeMillis() - startTime) + "ms");
|
// System.out.println(res);
|
||||||
|
// System.out.println("Executed At: " + (System.currentTimeMillis() - startTime) + "ms");
|
||||||
Observable<String> od = Observable.just("od").observeOn(Schedulers.io()).flatMap(
|
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(
|
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);
|
return Observable.merge(od, oe);
|
||||||
});
|
});
|
||||||
|
@ -51,8 +64,9 @@ public class TestRx {
|
||||||
// tasks join oc,(od_oe) and subscribe
|
// tasks join oc,(od_oe) and subscribe
|
||||||
Observable.merge(oc, od_oe).toBlocking().subscribe(
|
Observable.merge(oc, od_oe).toBlocking().subscribe(
|
||||||
res -> {
|
res -> {
|
||||||
System.out.println(res);
|
System.out.println("ss Thread: " + Thread.currentThread().getName());
|
||||||
System.out.println("Executed At: " + (System.currentTimeMillis() - startTime) + "ms");
|
// System.out.println(res);
|
||||||
|
// System.out.println("Executed At: " + (System.currentTimeMillis() - startTime) + "ms");
|
||||||
});
|
});
|
||||||
|
|
||||||
System.out.println("End executed: " + (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.Observable;
|
||||||
|
import rx.Subscriber;
|
||||||
|
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by lixiangrong on 2018/1/16.
|
* Created by lixiangrong on 2018/1/16.
|
||||||
* 链式函数式处理
|
* 链式函数式处理
|
||||||
*/
|
*/
|
||||||
public class TestRx01 {
|
public class TestRx01 {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) throws Exception {
|
||||||
hello(1, 2, 3, 4, 5);
|
// 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) {
|
private static void hello(Integer... integers) {
|
||||||
Observable<Integer> workflow = Observable.from(integers)
|
Observable<Integer> workflow = Observable.from(integers)
|
||||||
.filter(i -> (i < 10) && (i > 0))
|
.filter(i -> (i < 10) && (i > 0))
|
||||||
.map(i -> i * 2);
|
.map(i -> i * 2).reduce((x, y) -> x + y);
|
||||||
workflow.subscribe(i -> System.out.print(i + "! "));
|
|
||||||
System.out.println();
|
|
||||||
workflow.subscribe(i -> System.out.print(i + "! "));
|
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() {
|
cachedThreadPool.execute (new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
//System.out.println(index);
|
//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