diff --git a/README.md b/README.md index d1af570..d7f1609 100644 --- a/README.md +++ b/README.md @@ -21,9 +21,50 @@ short-server-common - 公共模块 short-server-pojo - dto/bo 用于模块之间的传输实体/领域模型定义 short-server-service - 短链生成服务 -#### 调用方式及API +#### 附加功能说明 + + 支持默认定时30天的清除短链(默认开启) + 支持带签名区分的短链形式,例如: + request: + { + "baseUrlAddr": "htttps://www.baidu.com/xxdsd/sdsdsds?sadsads=xxxx", + "variableList": [ + 13111112211, + 12111112222 + ] + } + response: + { + "status": 0, + "data": { + "shortChainResult": [ + "e4ig5miu1n|13111112211", + "rtyt8vhx6l|12111112222" + ]} + } + 也支持不带签名的短链(这里只支持单条调用) + request: + { + "baseUrlAddr": "htttps://www.baidu.com/xxdsd/sdsdsds?sadsads=xxxx" + } + response: + { + "status": 0, + "data": { + "shortChainResult": [ + "e4ig5miu1n" + ]} + } +#### 调用方式及API + + 批量生成短链API : {{host}}:{{ip}}/send + 短链兑换真实地址API : {{host}}:{{ip}}/返回的短链 #### 部署方式 - - + + by-short-server 目录下 mvn clean install 进行打包 + + 上传到服务器 + + 运行 ./script 下的 run-short-server.sh 脚本启动 diff --git a/pom.xml b/pom.xml index d8cda14..544726b 100644 --- a/pom.xml +++ b/pom.xml @@ -34,6 +34,7 @@ 1.2.73 1.18.16 3.8.1 + 2.3.2 @@ -72,6 +73,11 @@ commons-lang3 ${common-lang3.version} + + org.quartz-scheduler + quartz + ${quarz.version} + diff --git a/script/run-short-server.sh b/script/run-short-server.sh new file mode 100644 index 0000000..893282a --- /dev/null +++ b/script/run-short-server.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +source stop-short-server.sh +source start-short-server.sh diff --git a/script/start-short-server.sh b/script/start-short-server.sh new file mode 100644 index 0000000..07d08c4 --- /dev/null +++ b/script/start-short-server.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +echo "Start run short-server-service-1.0 Application..." + +nohup java -jar short-server-service-1.0-SNAPSHOT.jar 1> short-Log.log 2>log/short-errorLog.log & diff --git a/script/stop-short-server.sh b/script/stop-short-server.sh new file mode 100644 index 0000000..2d27cc8 --- /dev/null +++ b/script/stop-short-server.sh @@ -0,0 +1,12 @@ +#!/bin/bash + + +pid=`ps -ef | grep short-server-service-1.0-SNAPSHOT | grep -v grep| awk '{print $2}'` + +if [ -z "$pid" ]; +then + echo "Application is already stopped" $pid +else + echo $pid is killed + kill -9 $pid +fi diff --git a/short-server-common/pom.xml b/short-server-common/pom.xml index b5217e5..f7ac11d 100644 --- a/short-server-common/pom.xml +++ b/short-server-common/pom.xml @@ -35,6 +35,10 @@ org.apache.commons commons-lang3 + + org.quartz-scheduler + quartz + \ No newline at end of file diff --git a/short-server-common/src/main/java/com/by/utils/CronUtil.java b/short-server-common/src/main/java/com/by/utils/CronUtil.java new file mode 100644 index 0000000..d9e6852 --- /dev/null +++ b/short-server-common/src/main/java/com/by/utils/CronUtil.java @@ -0,0 +1,125 @@ +package com.by.utils; + +import org.quartz.CronExpression; + +import java.text.ParseException; + + +/** + * Cron表达式解析 + *

+ * 父类是关于操作定时任务的 + * + * @author q 直接哪里使用的,并不是本人写的,有点不符合代码规范 + */ +public class CronUtil { + + /** + * 装换成中文表示形式 + * @param cronExp + * @return + */ + public static String translateToChinese(String cronExp) { + if (cronExp == null || cronExp.length() < 1) { + return "cron表达式为空"; + } + CronExpression exp = null; + // 初始化cron表达式解析器 + try { + exp = new CronExpression(cronExp); + } catch (ParseException e) { + return "corn表达式不正确"; + } + String[] tmpCorns = cronExp.split(" "); + StringBuffer sBuffer = new StringBuffer(); + if (tmpCorns.length == 6) { + //解析月 + if (!tmpCorns[4].equals("*")) { + sBuffer.append(tmpCorns[4]).append("月"); + } else { + sBuffer.append("每月"); + } + //解析周 + if (!tmpCorns[5].equals("*") && !tmpCorns[5].equals("?")) { + char[] tmpArray = tmpCorns[5].toCharArray(); + for (char tmp : tmpArray) { + switch (tmp) { + case '1': + sBuffer.append("星期天"); + break; + case '2': + sBuffer.append("星期一"); + break; + case '3': + sBuffer.append("星期二"); + break; + case '4': + sBuffer.append("星期三"); + break; + case '5': + sBuffer.append("星期四"); + break; + case '6': + sBuffer.append("星期五"); + break; + case '7': + sBuffer.append("星期六"); + break; + case '-': + sBuffer.append("至"); + break; + default: + sBuffer.append(tmp); + break; + } + } + } + + //解析日 + if (!tmpCorns[3].equals("?")) { + if (!"*".equals(tmpCorns[3]) && !(tmpCorns[3]).contains("/")) { + sBuffer.append(tmpCorns[3]).append("日"); + }else if(!tmpCorns[3].equals("*") && (tmpCorns[3]).contains("/")){ + + String[] split = tmpCorns[3].split("/"); + if(split.length == 2 ){ + sBuffer.append("从第").append(split[0]).append("天开始,每").append(split[1]).append("天,"); + } + } + else { + sBuffer.append("每日"); + } + } + + //解析时 + if (!tmpCorns[2].equals("*")) { + sBuffer.append(tmpCorns[2]).append("时"); + } else { + sBuffer.append("每时"); + } + + //解析分 + if (!tmpCorns[1].equals("*")) { + sBuffer.append(tmpCorns[1]).append("分"); + } else { + sBuffer.append("每分"); + } + + //解析秒 + if (!tmpCorns[0].equals("*")) { + sBuffer.append(tmpCorns[0]).append("秒"); + } else { + sBuffer.append("每秒"); + } + } + + return sBuffer.append("执行").toString(); + + } + + public static void main(String[] args) { + String CRON_EXPRESSION = "0 0 0 1/1 * ?"; + System.out.println(CRON_EXPRESSION +" - "+CronUtil.translateToChinese(CRON_EXPRESSION)); + + } +} diff --git a/short-server-service/src/main/java/com/by/ShortServerApplication.java b/short-server-service/src/main/java/com/by/ShortServerApplication.java index ef9d01d..f299317 100644 --- a/short-server-service/src/main/java/com/by/ShortServerApplication.java +++ b/short-server-service/src/main/java/com/by/ShortServerApplication.java @@ -4,6 +4,7 @@ package com.by; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.annotation.EnableScheduling; /** * 项目启动入口 @@ -11,6 +12,7 @@ import org.springframework.scheduling.annotation.EnableAsync; * @author q */ @EnableAsync +@EnableScheduling @SpringBootApplication public class ShortServerApplication { public static void main(String[] args) { diff --git a/short-server-service/src/main/java/com/by/api/convert/ShortChainVOToDTOConvert.java b/short-server-service/src/main/java/com/by/api/convert/ShortChainVOToDTOConvert.java index f24b8b0..0f6c6ee 100644 --- a/short-server-service/src/main/java/com/by/api/convert/ShortChainVOToDTOConvert.java +++ b/short-server-service/src/main/java/com/by/api/convert/ShortChainVOToDTOConvert.java @@ -30,12 +30,15 @@ public class ShortChainVOToDTOConvert { Set originsUrlSet = new HashSet<>(1000); String baseUrlAddr = shortChainRequestVO.getBaseUrlAddr(); - shortChainRequestVO.getVariableList().forEach( - each -> { - originsUrlSet.add(baseUrlAddr + SymbolConstant.SPLIT_VERTICAL + each); - } - ); + if (CollectionUtil.isNotEmpty(shortChainRequestVO.getVariableList())){ + shortChainRequestVO.getVariableList().forEach( + each -> { + originsUrlSet.add(baseUrlAddr + SymbolConstant.SPLIT_VERTICAL + each); + } + + ); + } if (CollectionUtil.isNotEmpty(originsUrlSet)) { ShortChainDTO shortChainDTO = new ShortChainDTO(); diff --git a/short-server-service/src/main/java/com/by/api/vo/ShortChainRequestVO.java b/short-server-service/src/main/java/com/by/api/vo/ShortChainRequestVO.java index f63f1a7..df1e22e 100644 --- a/short-server-service/src/main/java/com/by/api/vo/ShortChainRequestVO.java +++ b/short-server-service/src/main/java/com/by/api/vo/ShortChainRequestVO.java @@ -6,7 +6,6 @@ import lombok.Data; import lombok.NoArgsConstructor; import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotEmpty; import java.util.List; @@ -29,6 +28,5 @@ public class ShortChainRequestVO { /** * 每一个需要进行短链拼接的变量内容集合 */ - @NotEmpty(message = RequestDetailConstant.REQUEST_PARAMS_EMPTY) private List variableList; } diff --git a/short-server-service/src/main/java/com/by/dao/ShortUrlRepository.java b/short-server-service/src/main/java/com/by/dao/ShortUrlRepository.java index f8b1f44..a970b81 100644 --- a/short-server-service/src/main/java/com/by/dao/ShortUrlRepository.java +++ b/short-server-service/src/main/java/com/by/dao/ShortUrlRepository.java @@ -7,6 +7,8 @@ import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; +import java.util.List; + /** * @author q */ @@ -22,4 +24,51 @@ public interface ShortUrlRepository extends JpaRepository, JpaSp @Modifying @Query("update ShortUrl t set t.sendTag = ?1 where t.id = ?2") void updateSendStatus(Integer sendStatus, Long recId); + + + /** + * @param expirationDay 查询大于参数的过期时间 + * @return 满足过期时间大于参数的集合 + */ + @Query + List findAllByExpirationDayAfter(Integer expirationDay); + + /** + * @param expirationDay 查询等于参数的过期时间 + * @return 满足过期时间等于参数的集合 + */ + @Query + List findAllByExpirationDay(Integer expirationDay); + + /** + * 批量把过期时间减一 + * + * @param ids 所有需要的id + * @return 更改的结果 + */ + @Modifying + @Query( value = "UPDATE ShortUrl t set t.expirationDay = t.expirationDay-1 WHERE t.id IN (?1)") + Integer batchUpdateExpirationDay(List ids); + + /** + * (软)删除过期时间为day的所有记录 - 推荐手动失效场景 + * + * @param ids 指定删除的时间 + * @return (软)删除的条数 + */ + @Modifying + @Query( value = "UPDATE ShortUrl t set t.validTag = 1 WHERE t.id IN (?1)") + Integer batchSoftDeleteExpirationDayIs(List ids); + + + /** + * (直接)删除过期时间为day的所有记录 - 过期后自动删除基本没有保存的必要 + * + * @param expirationDay 指定删除的时间 + * @return (直接)删除的条数 + */ + @Modifying + @Query( value = "DELETE FROM ShortUrl t WHERE t.expirationDay = ?1") + Integer batchDeleteExpirationDayIs(Integer expirationDay); + } \ No newline at end of file diff --git a/short-server-service/src/main/java/com/by/entity/constants/DBDefaultConstant.java b/short-server-service/src/main/java/com/by/entity/constants/DBDefaultConstant.java index 5b6dd18..4cfd5d7 100644 --- a/short-server-service/src/main/java/com/by/entity/constants/DBDefaultConstant.java +++ b/short-server-service/src/main/java/com/by/entity/constants/DBDefaultConstant.java @@ -15,6 +15,12 @@ public class DBDefaultConstant { */ public static final int ZERO_NUM_TAG = 0; + /** + * 0L + */ + public static final Long LONG_ZERO_NUM_TAG = 0L; + + /** * 1 */ diff --git a/short-server-service/src/main/java/com/by/service/ShortServerService.java b/short-server-service/src/main/java/com/by/service/ShortServerService.java index 59985e9..6a449e9 100644 --- a/short-server-service/src/main/java/com/by/service/ShortServerService.java +++ b/short-server-service/src/main/java/com/by/service/ShortServerService.java @@ -31,4 +31,9 @@ public interface ShortServerService { * @return */ boolean updateShortUrlToPlatformSendtatus(Long recId, boolean sucess); + + /** + * 按天更新短链的过期时间 默认是保存30天 + */ + Integer updateShortUrlRecOnDay(); } diff --git a/short-server-service/src/main/java/com/by/service/impl/ShortServerServiceImpl.java b/short-server-service/src/main/java/com/by/service/impl/ShortServerServiceImpl.java index dbf5fe1..ff72e22 100644 --- a/short-server-service/src/main/java/com/by/service/impl/ShortServerServiceImpl.java +++ b/short-server-service/src/main/java/com/by/service/impl/ShortServerServiceImpl.java @@ -1,5 +1,6 @@ package com.by.service.impl; +import cn.hutool.core.collection.CollectionUtil; import com.by.constants.SymbolConstant; import com.by.dao.ShortUrlDAO; import com.by.dao.ShortUrlRepository; @@ -16,10 +17,8 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Objects; +import java.util.*; +import java.util.stream.Collectors; /** * 短链服务实现Service @@ -52,7 +51,13 @@ public class ShortServerServiceImpl implements ShortServerService { makeShortUrlResult.forEach( (shortUrl, originUrl) -> { shortUrls.add(new ShortUrl(originUrl, shortUrl, DBDefaultConstant.ZERO_NUM_TAG, DBDefaultConstant.ZERO_NUM_TAG)); - resultShortUrls.add(shortUrl + SymbolConstant.SPLIT_VERTICAL + StringUtils.substringAfterLast(originUrl, SymbolConstant.SPLIT_VERTICAL)); + String orginSplit = StringUtils.substringAfterLast(originUrl, SymbolConstant.SPLIT_VERTICAL); + if (StringUtils.isNotBlank(orginSplit)){ + resultShortUrls.add(shortUrl + SymbolConstant.SPLIT_VERTICAL + orginSplit); + }else { + resultShortUrls.add(shortUrl); + } + } ); @@ -94,4 +99,24 @@ public class ShortServerServiceImpl implements ShortServerService { } return Boolean.TRUE; } + + @Override + @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW) + public Integer updateShortUrlRecOnDay() { + + Integer deleteCount = shortUrlRepository.batchDeleteExpirationDayIs(DBDefaultConstant.ZERO_NUM_TAG); + if (!Objects.isNull(deleteCount) && deleteCount > 0){ + log.info(" === [ShortServerServiceImpl|handleOriginUrlsToShortUrls, success delete expiration count is {} ] === ", deleteCount); + } + + List allByExpirationDayAfter = shortUrlRepository.findAllByExpirationDayAfter(DBDefaultConstant.ZERO_NUM_TAG); + + if (CollectionUtil.isEmpty(allByExpirationDayAfter)){ + return DBDefaultConstant.ZERO_NUM_TAG; + } + + return shortUrlRepository.batchUpdateExpirationDay(allByExpirationDayAfter.stream() + .map(ShortUrl::getId) + .collect(Collectors.toList())); + } } diff --git a/short-server-service/src/main/java/com/by/task/CheckShortUrlScheduleTask.java b/short-server-service/src/main/java/com/by/task/CheckShortUrlScheduleTask.java new file mode 100644 index 0000000..4331872 --- /dev/null +++ b/short-server-service/src/main/java/com/by/task/CheckShortUrlScheduleTask.java @@ -0,0 +1,41 @@ +package com.by.task; + +import com.by.service.ShortServerService; +import com.by.utils.CronUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +/** + * 检查并更新定时任务记录的Task + * + * @author q + */ +@Component +@Slf4j +public class CheckShortUrlScheduleTask { + + public static final String EXECUTE_CRON = "0 0 0 1/1 * ? "; + + private final ShortServerService shortServerService; + + public CheckShortUrlScheduleTask(ShortServerService shortServerService) { + this.shortServerService = shortServerService; + } + + /** + * 每天执行保存短链时间减一的操作 Task + */ + @Scheduled(cron = EXECUTE_CRON) + public void execute() { + log.info("=== [CheckShortUrlScheduleTask|execute is running. Cron rule is {}, Chinese translated to {} Thread is {} ] ===", + EXECUTE_CRON, + CronUtil.translateToChinese(EXECUTE_CRON), + Thread.currentThread().getName() + ); + + Integer updateRecCount = shortServerService.updateShortUrlRecOnDay(); + + log.info("=== [CheckShortUrlScheduleTask|execute update rec is {} . Thread is {} ] ===", updateRecCount, Thread.currentThread().getName()); + } +} diff --git a/short-server-service/src/test/java/com/by/DaoTest.java b/short-server-service/src/test/java/com/by/DaoTest.java new file mode 100644 index 0000000..9409d07 --- /dev/null +++ b/short-server-service/src/test/java/com/by/DaoTest.java @@ -0,0 +1,23 @@ +package com.by; + +import com.by.service.ShortServerService; +import lombok.extern.slf4j.Slf4j; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@Slf4j +@SpringBootTest +@RunWith(SpringRunner.class) +public class DaoTest { + + @Autowired + private ShortServerService shortServerService; + + @Test + public void test1(){ + System.out.println(shortServerService.updateShortUrlRecOnDay()); + } +}