import java.util.Stack;

public class MathUtils {
    private static char[] charSet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();


    /**
     * 将10进制转化为62进制
     *
     * @param number
     * @return
     */
    public static String _10_to_62(long number) {
        Long rest = Math.abs(number);
        Stack<Character> stack = new Stack<Character>();
        StringBuilder result = new StringBuilder(0);
        while (rest != 0) {
            stack.add(charSet[new Long((rest - (rest / 62) * 62)).intValue()]);
            rest = rest / 62;
        }
        for (; !stack.isEmpty(); ) {
            result.append(stack.pop());
        }

        String finalResult = result.toString();
//	 补0
//        if (result.length() < 6) {
//            finalResult = "000000" + result.toString();
//            finalResult = finalResult.substring(finalResult.length() - 6);
//        }
        return finalResult;

    }


    /**
     * 将62进制转换成10进制数
     *
     * @param ident62
     * @return
     */
    private static String convertBase62ToDecimal(String ident62) {
        int decimal = 0;
        int base = 62;
        int keisu = 0;
        int cnt = 0;

        byte ident[] = ident62.getBytes();
        for (int i = ident.length - 1; i >= 0; i--) {
            int num = 0;
            if (ident[i] > 48 && ident[i] <= 57) {
                num = ident[i] - 48;
            } else if (ident[i] >= 65 && ident[i] <= 90) {
                num = ident[i] - 65 + 10;
            } else if (ident[i] >= 97 && ident[i] <= 122) {
                num = ident[i] - 97 + 10 + 26;
            }
            keisu = (int) java.lang.Math.pow((double) base, (double) cnt);
            decimal += num * keisu;
            cnt++;
        }
        return String.format("%08d", decimal);
    }

}

使用 _10_to_62 方法传入一个数字就可以生成一个有序的字符串(传入的数字递增就可以实现无限不重复)
常用于生成短链接

生成短链思路

使用redis 集合(Set)储存生成的短链(短链池),每次使用一条就POP出来,数据库记录生成短链的最大值(_10_to_62 方法传入的数字的最大值), 定时检查redis 的短链池少于多少条就再往短链池中添加数据(_10_to_62 方法传入的数字由数据库记录最大值递增)

短链生产代码


import com.xxx.service.ShortUrlDataSupportService;
import com.xxx.utils.MathUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

@Component
@EnableScheduling
@Slf4j
public class RedisKeyPoolGenerateTasks {

    @Autowired
    ShortUrlDataSupportService redisDao;
    

    // 短链池的缓存名
    private static final String REDIS_POOL_KEY = "DWZ:URLPOOL";

    /**
     * 定时任务 5分钟执行一次
     */
    @Scheduled(fixedDelay = 5000)
    public void poolKeyCheckTask() {
        //短链池 小于10万条短链
        while (redisDao.getSize(REDIS_POOL_KEY) < 10000000) {
            // 每次生成10万条短链
            generatePoolKeys(100000);
            try {
                Thread.sleep(2 * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void generatePoolKeys(long count) {
        // 获取数据库保存的短链最大值
        Long maxNum = shortUrlPoolConfigMapper.readPoolMaxNum();

        long toNum = maxNum + count;
        List<String> addToRedis = new ArrayList<>();
        for (long begin = maxNum + 1; begin < toNum;
             begin++) {
            // 每 1000条保存一次
            if (begin % 1000 == 0) {
                // 更新数据库保存的短链最大值
                shortUrlPoolConfigMapper.updatePoolMaxNum(begin);
                redisDao.add(REDIS_POOL_KEY, addToRedis);
                addToRedis = new ArrayList<>();
                log.info("import to pool, current no is {}", begin);
            }
            addToRedis.add(MathUtils._10_to_62(begin));
        }
        // 更新数据库保存的短链最大值
        shortUrlPoolConfigMapper.updatePoolMaxNum(toNum);
	// 将短链插入redis
        redisDao.add(REDIS_POOL_KEY, addToRedis);
    }

}

redisDao 类


import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.support.atomic.RedisAtomicLong;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Component
public class ShortUrlDataSupportService {

    @Resource( name= "DwzPool")
    private RedisTemplate<String, Object> dwzPoolRedisTemplate;


    @Resource( name = "SeqGenerator")
    RedisTemplate seqRedisTemplate;


    /**
     * 新增一个  sadd
     *
     * @param key
     * @param value
     */
    public void add(String key, String value) {
        dwzPoolRedisTemplate.opsForSet().add(key, value);
    }

    /**
     * 新增一个  sadd
     *
     * @param key
     * @param values
     */
    public void add(String key, List<String> values) {
        dwzPoolRedisTemplate.opsForSet().add(key, values.toArray());
    }

    /**
     * 随机取一个
     *
     * @param key
     */
    public String getOne(String key) {
        return (String)dwzPoolRedisTemplate.opsForSet().pop(key);
    }

    /**
     * 随机取一个
     *
     * @param key
     */
    public long getSize(String key) {
        return dwzPoolRedisTemplate.opsForSet().size(key);
    }


    /**
     * @Description: 获取自增长值
     * @param key key
     * @return
     */
    public Long getIncr(String key) {
        RedisAtomicLong entityIdCounter = new RedisAtomicLong(key, seqRedisTemplate.getConnectionFactory());
        Long increment = entityIdCounter.getAndIncrement();
        entityIdCounter.persist();
        return increment;
    }

    /**
     * @Description: 初始化自增长值
     * @param key key
     * @param value 当前值
     */
    public void setIncr(String key, int value) {
        RedisAtomicLong counter = new RedisAtomicLong(key, seqRedisTemplate.getConnectionFactory());
        counter.set(value);
        counter.expire(0, TimeUnit.SECONDS);
    }

}

Q.E.D.