-
Notifications
You must be signed in to change notification settings - Fork 5
coderdream_20220507
CoderDream edited this page May 7, 2022
·
2 revisions
package com.coderdream.service.impl;
import com.coderdream.bean.ShortLinkBean;
import com.coderdream.generator.RandomStringGenerator;
import com.coderdream.helper.BloomFilterHelper;
import com.coderdream.helper.FileOperateHelper;
import com.coderdream.helper.GeneratorHelper;
import com.coderdream.helper.GuavaCacheHelper;
import com.coderdream.helper.ShortLinkHelper;
import com.coderdream.service.LinkService;
import com.coderdream.utils.Config;
import com.coderdream.utils.Constants;
import com.coderdream.utils.DuplicatedEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.HashSet;
import java.util.Set;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
@Service
@Slf4j
public class LinkServiceImpl implements LinkService {
@Resource
private Config config;
@Resource
private FileOperateHelper fleOperateHelper;
@Resource
private ShortLinkHelper shortLinkHelper;
@Resource
private GuavaCacheHelper guavaCacheHelper;
@Resource
private BloomFilterHelper bloomFilterHelper;
@Resource
private GeneratorHelper generatorHelper;
/**
* 号码生成器列表
*/
@Resource
private RandomStringGenerator randomStringGenerator;
private String generateCode;
private Set<String> hashCodeSet;
@PostConstruct
public void init() {
//stringGeneratorList = generatorHelper.createStringGenerator();
// generateCode = randomStringGenerator.generateCode();
hashCodeSet = new HashSet<>();
// machineId = Long.parseLong(fileOperateAbility.readFile("machineId"));
}
@Override
public String getShortLink(String longLink) {
// 校验longLink
if (longLink == null || "".equals(longLink)) {
// 记录日志
log.error("入参错误,不能为空:" + longLink);
return "";
}
// 获取机器ID,这里写在文件中,后期通过ZooKeeper管理
String machineId = fleOperateHelper.readFile("machineId");
// 生成短链接
String code = shortLinkHelper.createShortLinkCode(longLink);
// 记录日志
//log.error("缓存大小:" + guavaCacheHelper.size());
Long guavaCacheSize = guavaCacheHelper.size();
Long initSize = Constants.MAXIMUM_SIZE;
Float rate = Float.valueOf(guavaCacheSize) / Float.valueOf(initSize);
int randomBit = config.TOTAL_BIT - config.MACHINE_BIT - code.length();
// 记录日志
// log.error("目前缓存水位:" + rate);
// if (Constants.WATER_LEVEL < rate) {
generateCode = randomStringGenerator.generateCode(randomBit);
// }
// 机器ID作为前缀
code = machineId + generateCode + code;
// 创建短链接Bean
ShortLinkBean shortLinkBean = new ShortLinkBean();
shortLinkBean.setShortLink(code);
shortLinkBean.setLongLink(longLink);
shortLinkBean.setExpireTime(System.currentTimeMillis() + config.EXPIRE_SEC * 1000);
// 如果存在(可能误判)
if (bloomFilterHelper.mightContain(code)) {
// 从缓存中取对象
ShortLinkBean oldShortLinkBean = (ShortLinkBean) guavaCacheHelper.get(code);
// 如果不存在误判为存在,则直接将新的数据写入缓存中
if (oldShortLinkBean == null) {
// 把短链接放入Guava缓存中
guavaCacheHelper.put(code, shortLinkBean);
// 把短链接放入布隆过滤器
bloomFilterHelper.put(code);
// 记录日志
log.warn("布隆过滤器误判: new code: " + code + " ; new link: " + longLink);
}
// 如果确实存在
else {
String oldLongLink = oldShortLinkBean.getLongLink();
// 判断是否Hash冲突了(code相同,长链接url不同)
if (code.equals(oldShortLinkBean.getShortLink()) && !longLink.equals(oldLongLink)) {
String totalCode = code;
// 记录日志
log.warn("Hash冲突, old and new code: " + code + "; old link: " + oldLongLink + " ; new link: "
+ longLink);
// 构造新code、新link
// code加上枚举前缀后再取Hash,生成新的短链接
code = machineId + generateCode + shortLinkHelper.createShortLinkCode(
DuplicatedEnum.DUPLICATED.getKey() + "_" + code);
totalCode = totalCode + "_" + code;
log.error("TotalCode:" + totalCode);
hashCodeSet.add(totalCode);
// 长链接加上前缀
String newLongLink = DuplicatedEnum.DUPLICATED.getKey() + "_" + longLink;
log.error("Hash冲突解决: new code: " + code + "; old link: " + oldShortLinkBean.getLongLink()
+ " ; new link: " + newLongLink);
// 设置新的短链接
shortLinkBean.setShortLink(code);
// 设置新的长链接
shortLinkBean.setLongLink(newLongLink);
// 把短链接放入Guava缓存中
guavaCacheHelper.put(code, shortLinkBean);
// 把短链接放入布隆过滤器
bloomFilterHelper.put(code);
}
// 未冲突,已存在数据,不做处理,既不放到缓存中,也不放到过滤器中
else {
// 记录日志
log.info("已存在: code " + code + " ; longLink: " + longLink);
}
}
}
// 通过布隆过滤器判断:如果不存在(100%正确),则直接放入缓存中
else {
// 把短链接放入Guava缓存中
guavaCacheHelper.put(code, shortLinkBean);
// 把短链接放入布隆过滤器
bloomFilterHelper.put(code);
}
// 记录日志
// log.info("Hash冲突集合大小: " + hashCodeSet.size());
// 将短链接返回给调用方
return code;
}
@Override
public String getLongLink(String shortLink) {
// 校验
if (shortLink == null || "".equals(shortLink)) {
// 记录日志
log.error("入参错误,不能为空:" + shortLink);
return "";
}
// 从缓存中获取对象
ShortLinkBean shortLinkBean = (ShortLinkBean) guavaCacheHelper.get(shortLink);
// 如果不存在,则记日志,然后返回空
if (shortLinkBean == null) {
log.warn("缓存中不存在 " + shortLink + " 对应的长链接");
return "";
}
// 如果存在,处理长链接
else {
// 取出长链接
String longLink = shortLinkBean.getLongLink();
// 如果不存在Hash冲突标记,则直接返回长链接
if (!longLink.startsWith(DuplicatedEnum.DUPLICATED.getKey())) {
return longLink;
}
// 否则去掉冲突标记后再返回
else {
log.warn("去掉冲突标记后再返回:" + longLink);
longLink = longLink.replace(DuplicatedEnum.DUPLICATED.getKey() + "_", "");
}
// 将长链接返回给调用方
return longLink;
}
}
}
package com.coderdream.generator;
import com.coderdream.utils.Constants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;
/**
* 功能描述
*
* @since 2022-05-05
*/
@Slf4j
@Service
public class RandomStringGenerator {
private List<String> stringList = new ArrayList<>();
/**
*
* @param randomBit 随机字符串的位数
* @return
*/
public String generateCode(Integer randomBit) {
StringBuffer stringBuffer = new StringBuffer();
for (int i = 0; i < randomBit; i++) {
Random random = new Random();
int index = random.nextInt(Constants.CHARS.toCharArray().length);
stringBuffer.append(stringList.get(index));
}
return stringBuffer.toString();
}
public RandomStringGenerator() {
Integer queueSizeConfig = Constants.CHARS.toCharArray().length;
for (int i = 0; i < queueSizeConfig; i++) {
Character character = Constants.CHARS.toCharArray()[i];
stringList.add(character.toString());
}
System.out.println(stringList.size());
}
}
package com.example.demo.self;
import org.junit.Test;
import java.util.LinkedHashMap;
/**
* @author zhaodaowen
* @see <a href="http://www.roadjava.com">乐之者java</a>
*/
public class DemoTest {
/**
* 给定数组[1,2,3,4,5],数组的值为任意整数,包括0和负数,也可能相同,如多个0
* index为0,输出2*3*4*5;
* index为1,输出1*3*4*5;
* index为2,输出1*2*4*5;
* index为3,输出1*2*3*5;
* index为4,输出1*2*3*4;
* 时间复杂度为O(n),不能为O(n^2)
*/
@Test
public void test1() {
Integer[] numbers = new Integer[5];
numbers[0] = 0;
numbers[1] = 2;
numbers[2] = 3;
numbers[3] = 4;
numbers[4] = 5;
Integer[] multiSum = new Integer[5];
int result = 1;
int zeroCount = 1;
// for (int i = 0; i < 5; i++) {
// multi[i] =
// }
Integer[] resultNumbers = new Integer[5];
for (int i = 0; i < 5; i++) {
if (numbers[i] == 0) {
resultNumbers[i] = result;
} else {
resultNumbers[i] = result / numbers[i];
}
}
for (int i = 0; i < 5; i++) {
System.out.println(resultNumbers[i]);
}
}
/**
* 如何 JAVA不使用中间变量,实现两个数的交换
*/
@Test
public void test2() {
int x = 10;
int y = 15;
System.out.println("x=" + x + ";y=" + y);
x = x^y;
y = x^y;
x = x^y;
System.out.println("x=" + x + ";y=" + y);
}
@Test
public void test3() {
int x = 10;
int y = 15;
System.out.println("x=" + x + ";y=" + y);
x = x + y;
y = x - y;
x = x - y;
System.out.println("x=" + x + ";y=" + y);
}
}