Java后端实现短链接服务

Java后端实现短链接服务

Java短链接服务是一个基于Java编程语言开发的应用程序,能够将长网址转换为短网址。它的主要作用包括:
1、简化分享:短链接使得链接更易于分享,尤其是在字符限制的环境中(如社交媒体、短信等)。
2、数据跟踪与分析:通过短链接,服务提供商可以跟踪链接的点击量、来源、时间等信息,帮助用户分析流量来源。
3、提高用户体验:短链接更美观,便于记忆,提升了用户的访问体验。
4、防止链接被截断:长链接在某些情况下可能被截断,短链接可以避免这个问题。

首先引入依赖

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.8.26</version>
</dependency>
<dependency>
    <groupId>com.mybatis-flex</groupId>
    <artifactId>mybatis-flex-spring-boot-starter</artifactId>
    <version>1.10.5</version>
</dependency>
<dependency>
    <groupId>com.mybatis-flex</groupId>
    <artifactId>mybatis-flex-processor</artifactId>
    <version>1.10.5</version>
    <scope>provided</scope>
</dependency>

以下为一个简单的短链接服务代码示例:

短链接实体类

import com.fasterxml.jackson.annotation.JsonFormat;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
import lombok.Data;
import lombok.experimental.Accessors;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;

/**
 * @Description: 短链接实体类
 * @ClassName: UrlModel
 * @Author: ceshi
 * @Date: 2025/1/17 15:34
 * @Version: 1.0
 */
@Data
@Accessors(chain = true)
@Table("short_url")
public class UrlModel {

    @Id(keyType = KeyType.Auto)
    private Integer id;

    private String shortUrl;

    private String longUrl;

    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @Column(onInsertValue = "now()")
    private Date createTime;

    private int clickCount;
}

Mapper接口

import com.mybatisflex.core.BaseMapper;
import com.xiong.examine.model.UrlModel;
import org.apache.ibatis.annotations.Mapper;

/**
 * @Description: urlMapper接口
 * @ClassName: UrlMapper
 * @Author: ceshi
 * @Date: 2025/1/16 15:06
 * @Version: 1.0
 */
@Mapper
public interface UrlMapper extends BaseMapper<UrlModel> {
}

UrlService类

import com.mybatisflex.core.service.IService;
import com.xiong.examine.model.UrlModel;

/**
 * @Description: url服务类
 * @ClassName: UrlService
 * @Author: ceshi
 * @Date: 2025/1/17 15:40
 * @Version: 1.0
 */
public interface UrlService extends IService<UrlModel> {

    /**
     * 长链接生成短连接
     * @param longUrl
     * @return
     */
    String generateShortUrl(String longUrl);

    /**
     * 短链接跳转
     * @param shortUrl
     * @return
     */
    String redirect(String shortUrl);
}

UrlServiceImpl实现类

import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.xiong.examine.mapper.UrlMapper;
import com.xiong.examine.model.UrlModel;
import com.xiong.examine.service.UrlService;
import com.xiong.examine.util.HashUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description: UrlServiceImpl实现类
 * @ClassName: UrlService
 * @Author: ceshi
 * @Date: 2025/1/17 15:40
 * @Version: 1.0
 */
@Service
public class UrlServiceImpl extends ServiceImpl<UrlMapper, UrlModel> implements UrlService {

    @Autowired
    private UrlMapper urlMapper;

    private final String BASE_URL = "http://short.url/";

    private Map<String, UrlModel> urlMappingCache = new HashMap<>();

    /**
     * 长链接生成短链接
     * @param longUrl
     * @return
     */
    @Override
    public String generateShortUrl(String longUrl) {
        // 使用Murmurhash算法 + Base62编码生成短链
        String shortUrl = BASE_URL + HashUtils.hashToBase62(longUrl);
        UrlModel urlModel = new UrlModel();
        urlModel.setShortUrl(shortUrl);
        urlModel.setLongUrl(longUrl);
        urlModel.setCreateTime(new Date());
        urlModel.setClickCount(0);
        urlMapper.insert(urlModel);
        // 将短链接url放置缓存map中
        urlMappingCache.put(shortUrl, urlModel);
        return shortUrl;
    }

    /**
     * 点击短链接跳转,并统计次数
     * @param shortUrl
     * @return
     */
    @Override
    public String redirect(String shortUrl) {
        // 从缓存中取数据
        UrlModel urlModel = urlMappingCache.get(shortUrl);
        if (urlModel != null) {
            // 更新点击次数
            urlModel.setClickCount(urlModel.getClickCount() + 1);
            urlMapper.update(urlModel);
            return urlModel.getLongUrl();
        }
        return null;
    }
}

UrlController控制器

package com.xiong.examine.controller;

import com.xiong.examine.service.UrlService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

/**
 * @Description: 短链接服务
 * @ClassName: UrlController
 * @Author: ceshi
 * @Date: 2025/1/17 15:57
 * @Version: 1.0
 */
@RestController
@RequestMapping("api")
public class UrlController {

    @Autowired
    private UrlService urlService;

    /**
     * 长链接生成短链接
     * @param longUrl
     * @return
     */
    @PostMapping("shorten")
    public String shortenUrl(@RequestParam String longUrl) {
        return urlService.generateShortUrl(longUrl);
    }

    /**
     * 短链接点击跳转
     * @param shortUrl
     * @return
     */
    @PostMapping("redirect")
    public String redirect(@RequestParam String shortUrl) {
        return urlService.redirect(shortUrl);
    }
}

短链接生成工具类HashUtils

import cn.hutool.core.lang.hash.MurmurHash;

/**
 * @Description: 短链接生成工具类
 * @ClassName: HashUtils
 * @Author: ceshi
 * @Date: 2025/1/17 17:12
 * @Version: 1.0
 */
public class HashUtils {

    private static final char[] CHARS = new char[]{
            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
    };

    private static final int SIZE = CHARS.length;

    private static String convertDecToBase62(long num) {
        // 特殊情况处理:当数字为0时,返回"0"
        if (num == 0) return "0";
        StringBuilder sb = new StringBuilder();
        while (num > 0) {
            // 计算余数
            int i = (int) (num % SIZE);
            // 将余数映射到 Base62 字符
            sb.append(CHARS[i]);
            // 更新数字
            num /= SIZE;
        }
        // 逆序返回 Base62 编码结果
        return sb.reverse().toString();
    }

    /**
     * 使用Murmurhash算法 + Base62编码生成短链
     * @param str
     * @return
     */
    public static String hashToBase62(String str) {
        // 使用 MurmurHash 计算字符串的 32 位哈希值
        int i = MurmurHash.hash32(str);
        // 将负数转换为非负数
        long num = i < 0 ? Integer.MAX_VALUE - (long) i : i;
        // 将哈希值转换为 Base62 编码的短链接
        return convertDecToBase62(num);
    }
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小浣熊JUN

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值