-
Notifications
You must be signed in to change notification settings - Fork 5
short link coderdream
CoderDream edited this page Apr 26, 2022
·
1 revision
# 应用名称
spring.application.name=short-link
# 应用服务 WEB 访问端口
server.port=8088
#自定义进制
app.config.customSystem=62
#短链接总长度
app.config.totalBit=8
#机器占位
app.config.machineBit=1
#计数器占位
app.config.counterBit=1
#缓存过期时长
app.config.expireSec=3600
app.model=emit
# Maximum number of connections that the server accepts and processes at any given time.
server.tomcat.max-connections=400
# Maximum number of worker threads.
server.tomcat.threads.max=200
# Minimum number of worker threads.
server.tomcat.threads.min-spare=64
package com.coderdream.utils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
@Configuration
@Slf4j
public class Config {
/**
* 进制
*/
@Value("${app.config.customSystem}")
public Long CUSTOM_SYSTEM;
/**
* 总位数
*/
@Value("${app.config.totalBit}")
public Integer TOTAL_BIT;
/**
* 机器占位
*/
@Value("${app.config.machineBit}")
public Integer MACHINE_BIT;
/**
* 计数器占用的位数
*/
@Value("${app.config.counterBit}")
public Integer COUNTER_BIT;
/**
* 编码占用位数
*/
public Integer CODE_BIT;
/**
* 号个数最大值
*/
public Long CODE_NUM_MIX = 1L;
/**
* 计数器个数
*/
public Long COUNTER_CNT = 1L;
/**
* 短链缓存时长(s)
*/
@Value("${app.config.expireSec}")
public Long EXPIRE_SEC;
@PostConstruct
public void init() {
check();
CODE_BIT = TOTAL_BIT - MACHINE_BIT - COUNTER_BIT;
// 计算号池塘的最大值
for (int i = 0; i < CODE_BIT; i++) {
CODE_NUM_MIX *= CUSTOM_SYSTEM;
}
// 计算计数器个数
for (int i = 0; i < COUNTER_BIT; i++) {
COUNTER_CNT *= CUSTOM_SYSTEM;
}
}
private void check() {
if (TOTAL_BIT <= 0 || MACHINE_BIT < 0 || COUNTER_BIT <= 0) {
log.error("TOTAL_BIT={},MACHINE_BIT={},COUNTER_BIT={} 3参数存在不合理参数,请检查", TOTAL_BIT, MACHINE_BIT, COUNTER_BIT);
throw new RuntimeException("存在不合理参数");
}
if (TOTAL_BIT - MACHINE_BIT - COUNTER_BIT <= 0) {
log.error(
"TOTAL_BIT={},MACHINE_BIT={},COUNTER_BIT={} 3参数存在不合理导致TOTAL_BIT - MACHINE_BIT - COUNTER_BIT <= 0,请检查",
TOTAL_BIT, MACHINE_BIT, COUNTER_BIT);
throw new RuntimeException("存在不合理参数");
}
}
}
package com.coderdream.service.impl;
import com.coderdream.helper.GuavaCacheHelper;
import com.coderdream.model.ShortLinkBean;
import com.coderdream.service.LinkService;
import com.coderdream.utils.Config;
import com.coderdream.utils.ShortLinkComponent;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class LinkServiceImpl implements LinkService {
@Resource
private Config config;
@Resource
private ShortLinkComponent shortLinkComponent;
@Resource
private GuavaCacheHelper guavaCacheHelper;
@Override
public String getShortLink(String longLink) {
String code = shortLinkComponent.createShortLinkCode(longLink);
ShortLinkBean shortLinkBean = new ShortLinkBean();
shortLinkBean.setShortLink(code);
shortLinkBean.setLongLink(longLink);
shortLinkBean.setExpireTime(System.currentTimeMillis() + config.EXPIRE_SEC * 1000);
guavaCacheHelper.put(code, shortLinkBean);
return code;
}
@Override
public String getLongLink(String shortLink) {
Object value = guavaCacheHelper.get(shortLink);
if (value == null) {
return null;
}
return ((ShortLinkBean) value).getLongLink();
}
}
package com.coderdream.model;
import lombok.Data;
@Data
public class ShortLinkBean {
/**
* id
*/
private Long id;
/**
* 长连接
*/
private String longLink;
/**
* 长连接对应的短链接
*/
private String shortLink;
/**
* 短链接过期时间
*/
private Long expireTime;
}
package com.coderdream.helper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.util.ResourceUtils;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
/**
*
*/
@Service
@Slf4j
public class FileOperateHelper {
public String readFile(String fileName) {
ClassPathResource classPathResource = new ClassPathResource(fileName);
InputStream inputStream = null;
StringBuilder stringBuilder = new StringBuilder();
try {
inputStream = classPathResource.getInputStream();
char[] buf = new char[1024];
Reader r = new InputStreamReader(inputStream, "UTF-8");
while (true) {
int n = r.read(buf);
if (n < 0) {
break;
}
stringBuilder.append(buf, 0, n);
}
} catch (IOException e) {
log.error("file error", e);
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (Exception e) {
log.error("file close error", e);
}
}
}
return stringBuilder.toString();
}
public void writeFile(String fileName, String content) {
try {
String basePath = ResourceUtils.getURL("classpath:").getPath() + "/info/";
File fileExist = new File(basePath);
// 文件夹不存在,则新建
if (!fileExist.exists()) {
fileExist.mkdirs();
}
// 获取文件对象
File file = new File(basePath, fileName);
if (!file.exists()) {
file.createNewFile();
}
FileWriter fileWriter = new FileWriter(file);
fileWriter.write(content);
fileWriter.flush();
fileWriter.close();
} catch (Exception e) {
log.error("writeFile error", e);
}
}
}
package com.coderdream.helper;
import com.coderdream.utils.Config;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
@Service
@Slf4j
public class GuavaCacheHelper {
@Resource
private Config config;
private Cache<Object, Object> cache;
@PostConstruct
public void init() {
cache = CacheBuilder.newBuilder()
//设置并发级别为8,并发级别是指可以同时写缓存的线程数
.concurrencyLevel(8)
//设置缓存容器的初始容量为10
.initialCapacity(10)
//设置缓存最大容量为100,超过100之后就会按照LRU最近最少使用算法来移除缓存项,生产环境可设置为 100000000
.maximumSize(100000000)
//是否需要统计缓存情况,该操作消耗一定的性能,生产环境应该去除
.recordStats()
//设置写缓存后n秒钟过期
.expireAfterWrite(config.EXPIRE_SEC, TimeUnit.SECONDS)
//设置读写缓存后n秒钟过期,实际很少用到,类似于expireAfterWrite
//.expireAfterAccess(17, TimeUnit.SECONDS)
//只阻塞当前数据加载线程,其他线程返回旧值
//.refreshAfterWrite(13, TimeUnit.SECONDS)
//设置缓存的移除通知
.removalListener(notification -> {
log.info(notification.getKey() + " " + notification.getValue() + " 被移除,原因:" + notification.getCause());
})
//build方法中可以指定CacheLoader,在缓存不存在时通过CacheLoader的实现自动加载缓存
.build();
}
/**
* 获取缓存
*/
public Object get(String key) {
return StringUtils.isEmpty(key) ? null : cache.getIfPresent(key);
}
/**
* 放入缓存
*/
public void put(String key, Object value) {
if (StringUtils.isNotEmpty(key) && value != null) {
cache.put(key, value);
}
}
}