生成短链接算法
@Override
public String createShortLink(String longLink, String expireTime) {
String shortLink = "";
long longHash = Hashing.murmur3_32().hashString(longLink, StandardCharsets.UTF_8).padToLong();
long hash = longHash;
while (true) {
ShortLink sLink = queryByHash(hash);
if(null == sLink){
break;
}
if(longLink.equals(sLink.getLongLink())){
shortLink = sLink.getShortLink();
sLink.setExpireTime(DateUtil.localDateTime(expireTime, 0));
break;
}
long snowId = SnowFlakeUtil.getDefaultSnowFlakeId();
long snowHash = Hashing.murmur3_32().hashLong(snowId).padToLong();
hash = Math.abs(longHash - snowHash);
}
if(ParamUtil.isNotEmpty(shortLink)){
return shortLink;
}
return Base62Util.encode(hash);
}
短链接跳转
@GetMapping("/{shortLink}")
public void redirectLongLink(@PathVariable("shortLink") String shortLink, HttpServletResponse response){
if(ParamUtil.isEmpty(shortLink)){
return;
}
String longLink = shortLinkService.queryLongLink(shortLink);
if(ParamUtil.isEmpty(longLink)){
return;
}
try{
response.setStatus(301);
response.setHeader("Location", longLink);
} catch (Exception e){
e.printStackTrace();
}
}
工具类
public class Base62Util {
private static final char[] toBase62 = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
};
private static final String base62Str = String.valueOf(toBase62);
private static final int length = toBase62.length;
public static String encode(Long src){
if(null == src || src <= 0){
return null;
}
StringBuilder dst = new StringBuilder();
while (src > 0) {
dst.insert(0, toBase62[(int)(src % length)]);
src = src / length;
}
while (dst.length() < 6){
dst.insert(0, toBase62[0]);
}
return dst.toString();
}
public static Long decode(String dst){
if(ParamUtil.isEmpty(dst)){
return null;
}
long num = 0;
long factor = 1;
dst = new StringBuilder(dst).reverse().toString();
for(char ch : dst.toCharArray()){
num += base62Str.indexOf(ch) * factor;
factor *= length;
}
return num;
}
}
public class SnowFlakeUtil {
private static final long START_STMP = 1420041600000L;
private static final long SEQUENCE_BIT = 9L;
private static final long MACHINE_BIT = 2L;
private static final long DATACENTER_BIT = 2L;
private static final long MAX_SEQUENCE = 511L;
private static final long MAX_MACHINE_NUM = 3L;
private static final long MAX_DATACENTER_NUM = 3L;
private static final long MACHINE_LEFT = 9L;
private static final long DATACENTER_LEFT = 11L;
private static final long TIMESTMP_LEFT = 13L;
private long datacenterId;
private long machineId;
private long sequence = 0L;
private long lastStmp = -1L;
public SnowFlakeUtil(long datacenterId, long machineId) {
if (datacenterId <= 3L && datacenterId >= 0L) {
if (machineId <= 3L && machineId >= 0L) {
this.datacenterId = datacenterId;
this.machineId = machineId;
} else {
throw new IllegalArgumentException("machineId can't be greater than MAX_MACHINE_NUM or less than 0");
}
} else {
throw new IllegalArgumentException("datacenterId can't be greater than MAX_DATACENTER_NUM or less than 0");
}
}
public synchronized long nextId() {
long currStmp = this.getNewstmp();
if (currStmp < this.lastStmp) {
throw new RuntimeException("Clock moved backwards. Refusing to generate id");
} else {
if (currStmp == this.lastStmp) {
this.sequence = this.sequence + 1L & 511L;
if (this.sequence == 0L) {
currStmp = this.getNextMill();
}
} else {
this.sequence = 0L;
}
this.lastStmp = currStmp;
return currStmp - 1420041600000L << 13 | this.datacenterId << 11 | this.machineId << 9 | this.sequence;
}
}
private long getNextMill() {
long mill;
for(mill = this.getNewstmp(); mill <= this.lastStmp; mill = this.getNewstmp()) {
}
return mill;
}
private long getNewstmp() {
return System.currentTimeMillis();
}
public static Long getDefaultSnowFlakeId() {
return ((SnowFlakeUtil) Singleton.get(SnowFlakeUtil.class, new Object[]{1L, 1L})).nextId();
}
public static void main(String[] args) {
for(int i = 0; i < 10; ++i) {
System.out.println(getDefaultSnowFlakeId());
System.out.println(getDefaultSnowFlakeId().toString().length());
}
}