JAVA 短链码生成工具类

简介: JAVA 短链码生成工具类

ConversionUtils.java


包含:


自增id转换方法


MD5+BASE64转换方法


import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
/**
 * @Author : JCccc
 * @CreateTime : 2019/12/6
 * @Description :
 *  短链接生成
 *  10进制,62进制互转
 **/
@Slf4j
public class ConversionUtils {
    /**
     * 初始化 62 进制数据,索引位置代表字符的数值,比如 A代表10,z代表61等
     */
    private static String chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    private static int scale = 62;
    /**
     * 将数字转为62进制
     *
     * @param num    Long 型数字
     * @param length 转换后的字符串长度,不足则左侧补0
     * @return 62进制字符串
     */
    public static String encode(long num, int length) {
        StringBuilder sb = new StringBuilder();
        int remainder;
        // id混淆算法
        long snum = num & 0xff000000;
        snum += (num & 0x0000ff00) << 8;
        snum += (num & 0x00ff0000) >> 8;
        snum += (num & 0x0000000f) << 4;
        snum += (num & 0x000000f0) >> 4;
        while (snum > scale - 1) {
            /*
              对 scale 进行求余,然后将余数追加至 sb 中,由于是从末位开始追加的,因此最后需要反转(reverse)字符串
             */
            remainder = Long.valueOf(snum % scale).intValue();
            sb.append(chars.charAt(remainder));
            snum = snum / scale;
        }
        sb.append(chars.charAt(Long.valueOf(snum).intValue()));
        String value = sb.reverse().toString();
        log.info("encode id: {}", snum);
        return StringUtils.leftPad(value, length, '0');
    }
    /**
     * 62进制字符串转为数字
     *
     * @param str 编码后的62进制字符串
     * @return 解码后的 10 进制字符串
     */
    public static long decode(String str) {
        /*
          将 0 开头的字符串进行替换
         */
        str = str.replace("^0*", "");
        long num = 0;
        int index;
        for (int i = 0; i < str.length(); i++) {
            /*
              查找字符的索引位置
             */
            index = chars.indexOf(str.charAt(i));
            /*
              索引位置代表字符的数值
             */
            num += (long) (index * (Math.pow(scale, str.length() - i - 1)));
        }
        // id混淆算法
        long snum = num & 0xff000000;
        snum += (num & 0x00ff0000) >> 8;
        snum += (num & 0x0000ff00) << 8;
        snum += (num & 0x000000f0) >> 4;
        snum += (num & 0x0000000f) << 4;
        return snum;
    }
    public static String Md5CodeEncode(String longUrl, int urlLength) {
        if (urlLength < 4 ) {
            urlLength = 8;// defalut length
        }
        StringBuilder sbBuilder = new StringBuilder(urlLength + 2);
        String md5Hex = "";
        int nLen = 0;
        while (nLen < urlLength) {
            // 这个方法是先 md5 再 base64编码 参见
            // https://github.com/ndxt/centit-commons/blob/master/centit-utils/src/main/java/com/centit/support/security/Md5Encoder.java
            md5Hex = Md5Encoder.encodeBase64(md5Hex + longUrl);
            for(int i=0;i<md5Hex.length();i++){
                char c = md5Hex.charAt(i);
                if(c != '/' && c != '+'){
                    sbBuilder.append(c);
                    nLen ++;
                }
                if(nLen == urlLength){
                    break;
                }
            }
        }
        return sbBuilder.toString();
    }
    public static void main(String[] args) {
        System.out.println("62进制:" + encode(1000000001L, 6));
        System.out.println("10进制:" + decode("15t2ps"));
        System.out.println( Md5CodeEncode("http://abcd.cn/JCccc.html",6));
    }
}


Md5Encoder.java


import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
 * @Author : JCccc
 * @CreateTime : 2019/11/27
 * @Description :
 **/
public abstract class Md5Encoder {
    private Md5Encoder() {
        throw new IllegalAccessError("Utility class");
    }
    protected static final Logger logger = LoggerFactory.getLogger(Md5Encoder.class);
    public static byte[] rawEncode(byte[] data){
        MessageDigest MD5;
        try {
            MD5 = MessageDigest.getInstance("MD5");
            MD5.update(data, 0, data.length);
            return MD5.digest();
        } catch (NoSuchAlgorithmException e) {
            logger.error(e.getMessage(),e);//e.printStackTrace();
            return null;
        }
    }
    public static String encode(byte[] data){
        byte [] md5Code = rawEncode(data);
        if(md5Code!=null){
            return new String(Hex.encodeHex(md5Code));
        } else {
            return null;
        }
    }
    public static String encode(String data){
        try {
            return encode(data.getBytes("utf8"));
        } catch (UnsupportedEncodingException e) {
            logger.error(e.getMessage(),e);//e.printStackTrace();
            return null;
        }
    }
    /**
     * 将md5 编码进行base64编码,去掉最后的两个==,16位的md5码base64后最后两位肯定是==
     * @param data 需要编码的 数据
     * @param urlSafe 返回url合法字符
     * @return 将md5 编码进行base64编码,去掉最后的两个==
     */
    public static String encodeBase64(byte[] data, boolean urlSafe){
        byte [] md5Code = rawEncode(data);
        if(md5Code != null){
            return new String(
                    urlSafe? Base64.encodeBase64URLSafe(md5Code): Base64.encodeBase64(md5Code),0,22);
        } else {
            return null;
        }
    }
    public static String encodeBase64(byte[] data){
        return encodeBase64(data, false);
    }
    public static String encodeBase64(String data, boolean urlSafe){
        try {
            return encodeBase64(data.getBytes("utf8"), urlSafe);
        } catch (UnsupportedEncodingException e) {
            logger.error(e.getMessage(),e);//e.printStackTrace();
            return null;
        }
    }
    public static String encodeBase64(String data){
        return encodeBase64(data, false);
    }
    /**
     * encoding password for spring security
     * 目前框架中的密码都是这样加密的
     * @param data  密文
     * @param salt  盐
     * @return 散列值
     */
    public static String encodePasswordAsSpringSecurity(String data,String salt){
        return encode(data + "{" + salt + "}");
    }
    /**
     * encoding password for spring JA-SIG Cas
     * @param data  密文
     * @param salt  盐
     * @param iterations 迭代次数
     * @return 散列值
     */
    public static String encodePasswordAsJasigCas(String data,String salt, int iterations){
        MessageDigest MD5;
        try {
            MD5 = MessageDigest.getInstance("MD5");
            byte[] saltBytes = salt.getBytes("utf8");
            MD5.update(saltBytes, 0, saltBytes.length);
            byte[] hashedBytes = MD5.digest(data.getBytes("utf8"));
            for(int i=0;i<iterations-1;i++)
                hashedBytes = MD5.digest(hashedBytes);
            return new String(Hex.encodeHex(hashedBytes));
        } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
            logger.error(e.getMessage(),e);//e.printStackTrace();
            return null;
        }
    }
    /**
     * 先腾框架默认的密码算法
     * @param data  密文
     * @param salt  盐
     * @return 散列值
     */
    public static String encodePassword(String data,String salt){
        return encodePasswordAsSpringSecurity(data , salt);
    }
    /**
     * 先腾框架双重加密算法: 客户端 用md5将密码加密一下传输到后台,后台将密码再用salt加密一下放入数据库中
     *         这个算法可以用于后台设置密码时使用,正常验证和以前一样。
     * @param data  密文
     * @param salt  盐
     * @return 散列值
     */
    public static String encodePasswordWithDoubleMd5(String data,String salt){
        return encodePasswordAsSpringSecurity(
                encode(data) , salt);
    }
}
相关文章
|
29天前
|
缓存 前端开发 Java
【前端学java】java基础巩固复习巩固语法练习-工具类的封装(14)
【8月更文挑战第10天】java基础巩固,工具类的封装
17 1
【前端学java】java基础巩固复习巩固语法练习-工具类的封装(14)
|
16天前
|
Java
Java应用结构规范问题之在UnitConvertUtils工具类将千米转换为米的问题如何解决
Java应用结构规范问题之在UnitConvertUtils工具类将千米转换为米的问题如何解决
|
28天前
|
存储 设计模式 安全
Java GenericObjectPool 对象池化技术--SpringBoot sftp 连接池工具类
Java GenericObjectPool 对象池化技术--SpringBoot sftp 连接池工具类
17 0
|
2月前
|
设计模式 存储 安全
Java面试题:设计一个线程安全的单例类并解释其内存占用情况?使用Java多线程工具类实现一个高效的线程池,并解释其背后的原理。结合观察者模式与Java并发框架,设计一个可扩展的事件处理系统
Java面试题:设计一个线程安全的单例类并解释其内存占用情况?使用Java多线程工具类实现一个高效的线程池,并解释其背后的原理。结合观察者模式与Java并发框架,设计一个可扩展的事件处理系统
43 1
|
2月前
|
安全 Java 开发者
Java中的并发工具类与线程安全实现
Java中的并发工具类与线程安全实现
|
3月前
|
设计模式 缓存 算法
编写高效的Java工具类:实用技巧与设计模式
编写高效的Java工具类:实用技巧与设计模式
|
2月前
|
并行计算 Java API
Java中的并发工具类详解
Java中的并发工具类详解
|
2月前
|
设计模式 缓存 算法
编写高效的Java工具类:实用技巧与设计模式
编写高效的Java工具类:实用技巧与设计模式
|
3月前
|
Java
JAVA工具类匹配重复或者连续的字符和符号
JAVA工具类匹配重复或者连续的字符和符号
|
3月前
|
算法 Java
基于java雪花算法工具类SnowflakeIdUtils-来自chatGPT
基于java雪花算法工具类SnowflakeIdUtils-来自chatGPT