废话不多说,直接上代码,直接可用
/**
* <p>
* 短连接表
* </p>
*
* @author system
* @since 2024-09-11
*/
@Getter
@Setter
@Accessors(chain = true)
@TableName("sms_short_url")
public class SmsShortUrl extends Model<SmsShortUrl> {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 原始连接
*/
@TableField("org_url")
private String orgUrl;
/**
* 生成带参数的原始连接
*/
@TableField("org_generate_url")
private String orgGenerateUrl;
/**
* 短网址url
*/
@TableField("short_url")
private String shortUrl;
/**
* 短网址标记
*/
@TableField("short_target")
private String shortTarget;
/**
* 业务参数
*/
@TableField("biz_param")
private String bizParam;
/**
* 状态(0:无效,1:有效)
*/
@TableField("status")
private Integer status;
/**
* 到期时间
*/
@TableField("invalid_time")
private LocalDateTime invalidTime;
/**
* 创建时间
*/
@TableField("create_time")
private LocalDateTime createTime;
/**
* 更新时间
*/
@TableField("update_time")
private LocalDateTime updateTime;
/**
* 逻辑删除字段 0未删除 1已删除
*/
@TableField("is_delete")
@TableLogic
private Integer isDelete;
/**
* 修改人
*/
@TableField("update_user")
private String updateUser;
@Override
public Serializable pkVal() {
return this.id;
}
}
/**
* <p>
* 短连接表 服务类
* </p>
*
* @author system
* @since 2024-09-11
*/
public interface SmsShortUrlService extends IService<SmsShortUrl> {
/**
* 生成短链接
* @param shortUrlReq
* @return
*/
String getShortUrl(ShortUrlReq shortUrlReq);
/**
* 根据短网址解析原网址
*/
ShortUrlVO getByShortUrl(String shortUrl);
/**
* 根据短网址target标记解析原网址
*/
ShortUrlVO getByTarget(String shortTarget);
}
/**
* <p>
* 短连接表 服务实现类
* </p>
*
* @author system
* @since 2024-09-11
*/
@Slf4j
@Service
public class SmsShortUrlServiceImpl extends ServiceImpl<SmsShortUrlMapper, SmsShortUrl> implements SmsShortUrlService {
@Resource
private RedisCommand redisCommand;
@Value("${shortUrl.server:t.eleshell.com}")
private String shortUrlServer;
private final static String chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
@Override
public String getShortUrl(ShortUrlReq shortUrlReq) {
String orgUrl = shortUrlReq.getOrgUrl();
String newOrgUrl = UrlUtils.formatUrl(shortUrlReq.getOrgUrl(), shortUrlReq.getBizParam());
Long id = IdGeneratorUtil.nextId();
String target = toShortTarget(id);
SmsShortUrl smsShortUrl = new SmsShortUrl();
smsShortUrl.setId(id);
smsShortUrl.setOrgUrl(orgUrl);
smsShortUrl.setOrgGenerateUrl(newOrgUrl);
smsShortUrl.setShortUrl(shortUrlServer + "/" + target);
smsShortUrl.setShortTarget(target);
smsShortUrl.setBizParam(shortUrlReq.getBizParam());
save(smsShortUrl);
String key = RedisKey.SHORT_URL + target;
redisCommand.set(key, JSON.toJSONString(smsShortUrl), 1, TimeUnit.DAYS);
return target;
}
@Override
public ShortUrlVO getByShortUrl(String shortUrl) {
if (!shortUrl.contains(shortUrlServer)) {
throw new BusinessException("短链接不合法");
}
int lastSlashIndex = shortUrl.lastIndexOf('/');
if (lastSlashIndex == -1) {
return null;
}
return getByTarget(shortUrl.substring(lastSlashIndex + 1));
}
@Override
public ShortUrlVO getByTarget(String shortTarget) {
String srcUrl = redisCommand.get(RedisKey.SHORT_URL + shortTarget);
if (!StringUtils.isEmpty(srcUrl)) {
return JSON.parseObject(srcUrl, ShortUrlVO.class);
}
SmsShortUrl smsShortUrl = getOne(Wrappers.lambdaQuery(SmsShortUrl.class)
.eq(SmsShortUrl::getShortTarget, shortTarget)
.last(" limit 1"));
if (!ObjectUtil.isNull(smsShortUrl)) {
return BeanUtil.toBean(smsShortUrl, ShortUrlVO.class);
}
return null;
}
public String toShortTarget(long number) {
// 将数字转换为字符串以进行哈希
String input = Long.toString(number);
// 使用MD5哈希(可以选择SHA-256或其他算法)
String hash = SecureUtil.md5(input);
// 从哈希结果中取前8位字符
return hash.substring(0, 8);
}
}
/**
* <p>
* 短连接表 前端控制器
* </p>
*
* @author system
* @since 2024-09-11
*/
@Slf4j
@RestController
@RequestMapping("/shortUrl")
@RequiredArgsConstructor
public class SmsShortUrlController {
private final SmsShortUrlService smsShortUrlService;
@ApiOperation(value = "生成短链接")
@PostMapping(value = "/getShortUrl")
public ResultData<String> getShortUrl(@RequestBody @Validated ShortUrlReq shortUrlReq) {
return ResultData.ok(smsShortUrlService.getShortUrl(shortUrlReq));
}
@ApiOperation(value = "根据短网址解析原网址")
@GetMapping(value = "/getByShortUrl")
public ResultData<ShortUrlVO> getByShortUrl(@RequestParam("shortUrl") String shortUrl) {
return ResultData.ok(smsShortUrlService.getByShortUrl(shortUrl));
}
@ApiOperation(value = "通过生成后的target标记解析原网址")
@GetMapping(value = "/getByTarget")
public ResultData<ShortUrlVO> getByTarget(@RequestParam("shortTarget") String shortTarget) {
return ResultData.ok(smsShortUrlService.getByTarget(shortTarget));
}
}
@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("/")
@Api(tags = "重定向链接")
public class RedirectController {
private final SmsShortUrlService smsShortUrlService;
@ApiOperation(value = "跳转链接")
@GetMapping(value = "/{target}")
public ResultData<Void> linkTo(@PathVariable("target") String target, HttpServletResponse response) {
try {
ShortUrlVO shortUrlVO = smsShortUrlService.getByTarget(target);
if(ObjectUtil.isNull(shortUrlVO) || StrUtil.isEmpty(shortUrlVO.getOrgUrl())) {
return ResultData.ok();
}
String encodeRedirectURL = response.encodeRedirectURL(shortUrlVO.getOrgUrl());
log.info("#linkTo encodeRedirectURL:{}", encodeRedirectURL);
response.sendRedirect(encodeRedirectURL);
} catch (IOException e) {
log.error("#linkTo redirect error:", e);
}
return ResultData.ok();
}
}