Java之SpringBoot短链接生成

本文介绍了一个基于Dubbo实现的短链接服务,包括生成短链、获取完整链接和增加点击计数的功能。服务中使用了Redis和MySQL进行数据存储,并通过 Scheduled 定时任务清理过期短链。同时,通过线程池异步处理短链点击量的增加,确保高并发场景下的性能。
摘要由CSDN通过智能技术生成

1、IShortUrlService 接口类

 

public interface IShortUrlService {

    /**
     * 生成短链
     *
     * @param shortUrlRequest
     * @return
     */
    String shortUrlGenerator(ShortUrlRequest shortUrlRequest);

    /**
     * 根据短链获取完整链接
     *
     * @param shortUrl
     * @return
     */
    String getUrl(String shortUrl);

    /**
     * 增加短链点击量
     *
     * @param shortUrl
     * @return
     */
    Boolean addClickCount(String shortUrl);
}

2、ShortUrlServiceImpl 接口实现类

@DubboService
public class ShortUrlServiceImpl implements IShortUrlService {

    private static final Logger log = LoggerFactory.getLogger(ShortUrlServiceImpl.class);

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    @Resource
    private ShortUrlMapper shortUrlMapper;

    @Resource
    private SpringApplicationContext springApplicationContext;

    /**
     * 域名匹配正则表达式
     */
    private static final Pattern DOMAIN_NAME_PATTERN = Pattern.compile("http(s)?://[\\w-]+[.\\w-]+(/)?");

    @Override
    public String shortUrlGenerator(ShortUrlRequest shortUrlRequest) {
        String fullUrl = shortUrlRequest.getFullUrl();
        if (ObjectUtils.isEmpty(fullUrl)) {
            throw new BaseException(500, "链接不能为空");
        }
        String[] shortUrls = ShortUrlUtil.generator(fullUrl);
        for (String shortUrl : shortUrls) {
            // 判断短链是否已存在
            String url = springApplicationContext.getBean(IShortUrlService.class).getUrl(shortUrl);
            if (url != null) {
                if (!url.equals(shortUrlRequest.getFullUrl())) {
                    continue;
                }
                return shortUrl;
            }
            // 保存长链接与短链接短对应关系
            ShortUrl shortUrlEntity = new ShortUrl();
            shortUrlEntity.setFullUrl(fullUrl);
            shortUrlEntity.setShotCode(shortUrl);
            shortUrlEntity.setExpirationDate(shortUrlRequest.getExpirationDate());
            Matcher matcher = DOMAIN_NAME_PATTERN.matcher(fullUrl);
            if (!matcher.find()) {
                throw new BaseException(500, "链接解析失败");
            }
            String baseUrl = matcher.group();
            shortUrlEntity.setBaseUrl(baseUrl);
            shortUrlEntity.setSuffixUrl(fullUrl.substring(baseUrl.length() - 1));
            shortUrlMapper.insert(shortUrlEntity);
            return shortUrl;
        }
        throw new BaseException(500, "链接生成失败");
    }

    @Override
    @Cacheable(cacheNames = "shortUrl", key = "#shortUrl", unless = "#result == null")
    public String getUrl(String shortUrl) {
        QueryWrapper<ShortUrl> shortUrlQw = new QueryWrapper<>();
        shortUrlQw.eq("shot_code", shortUrl);
        shortUrlQw.eq("del_flag", DelFlag.NORMAL);
        ShortUrl url = shortUrlMapper.selectOne(shortUrlQw);
        return url == null ? null : url.getFullUrl();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean addClickCount(String shortUrl) {
        QueryWrapper<ShortUrl> shortUrlQw = new QueryWrapper<>();
        shortUrlQw.eq("shot_code", shortUrl);
        shortUrlQw.eq("del_flag", DelFlag.NORMAL);
        ShortUrl url = shortUrlMapper.selectOne(shortUrlQw);
        if (url == null) {
            return false;
        }
        url.setTotalClickCount(url.getTotalClickCount() + 1);
        return shortUrlMapper.updateById(url) > 0;
    }

    @Scheduled(cron = "0 0 3 * * * ")
    public void removeShortUrl() {
        QueryWrapper<ShortUrl> queryWrapper = new QueryWrapper<>();
        queryWrapper.le("expirationDate", DateUtil.getTime());
        List<ShortUrl> shortUrls = shortUrlMapper.selectList(queryWrapper);
        //删除缓存数据库
//        for (ShortUrl shortUrl : shortUrls) {
//            redisTemplate.delete(shortUrl.getShotCode());
//        }
        List<Long> shortUrlIds = shortUrls.stream().map(ShortUrl::getId).collect(Collectors.toList());
        //删除mysql数据库
        shortUrlMapper.deleteBatchIds(shortUrlIds);
//        try {
//            Thread.sleep(1000);
//            //再次删除缓存数据库
//            for (ShortUrl shortUrl : shortUrls) {
//                redisTemplate.delete(shortUrl.getShotCode());
//            }
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
    }
}

3、ShortUrlHandler 工具类

public class ShortUrlHandler implements Runnable{
    private final IShortUrlService  shortUrlService;
    private final String shortUrl;

    public ShortUrlHandler(IShortUrlService shortUrlService, String shortUrl) {
        this.shortUrlService = shortUrlService;
        this.shortUrl = shortUrl;
    }

    @Override
    public void run() {
        shortUrlService.addClickCount(shortUrl);
    }
}

4、ShortUrlController 控制器类

@RestController
@RequestMapping("/api/shortUrl")
@Api(tags = {"C端-短链接"})
@RefreshScope
public class ShortUrlController extends BaseController {
    @DubboReference
    private IShortUrlService shortUrlService;
    @Resource
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
    //short-utl:
    //    prefix: http://test.gateway.yaotiao.net/coupon-provider/api/shortUrl/redirect/
    @Value("${short-utl.prefix:https://gateway.jumituangou.com/coupon-provider/api/shortUrl/redirect/}")
    private String prefixUrl;

    @GetMapping("/generator")
    @ApiOperation("生成短链")
    public ResponseResult<String> shortUrlGenerator(ShortUrlRequest shortUrlRequest) {
        shortUrlRequest.setExpirationDate(DateUtil.getDateAfterDay(new Date(), 60));
        String shortUrl = prefixUrl + shortUrlService.shortUrlGenerator(shortUrlRequest);
        return success(shortUrl);
    }

    @GetMapping("/redirect/{shortUrl}")
    @ApiOperation("短链重定向")
    @IgnoreUrlsAnnon("/api/shortUrl/") //白名单
    public void redirect(@PathVariable String shortUrl, HttpServletResponse response) {
        String url = shortUrlService.getUrl(shortUrl);
        try {
            response.sendRedirect(url);
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 异步增加短链点击次数
        ShortUrlHandler shortUrlHandler = new ShortUrlHandler(shortUrlService, shortUrl);
        threadPoolTaskExecutor.execute(shortUrlHandler);
    }
}

5、mysql 表 short_url;

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SpringBoot是一个开源的Java框架,可以简化Java应用程序的开发。它提供了很多方便的功能,可以帮助我们快速构建稳定可靠的应用程序。 要实现短链生成和统计,可以借助SpringBoot的特性和第三方库来完成。以下是一个基本的实现思路: 1. 短链生成 首先,我们需要设计一个用于生成短链的算法或方法。常见的方法是将长链接通过哈希算法转换为字符串。你可以选择使用MD5、SHA1等哈希算法,并取其中一部分字符作为短链接。另外,为了避免生成过长的短链,可以将其进一步进行压缩。 在SpringBoot中,可以通过创建一个生成短链的Controller来实现。Controller接收长链接作为参数,调用短链生成的方法,然后将生成短链接返回给前端。 2. 短链重定向 当用户点击短链接时,服务器需要将其重定向到原始的长链接地址。可以在SpringBoot中创建一个Controller,设置一个路由映射,并在该Controller中获取短链接对应的长链接,然后进行重定向。 3. 统计短链点击量 为了统计短链的点击量,我们可以在数据库中创建一个表,用于记录短链的相关信息,例如短链、长链接、点击次数等。 在SpringBoot中,可以定义一个点击事件的Controller,当用户点击短链时,将触发该Controller。该Controller负责将点击事件信息保存至数据库,并更新短链对应的点击次数。 以上是一个基本的实现思路,你可以根据具体需求和场景进行进一步的优化和改进。希望对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值