`

产生Id

 
阅读更多
public class IdWorker {
    // worker编号位数
    private static final long WORKER_BITS = 6L;

    // worker编号最大值,决定支持的部署节点数量
    private static final long MAX_WORKER_ID = -1L ^ (-1L << WORKER_BITS);

    // 毫秒内自增位数,每毫秒最大序号支持65535
    private static final long SEQUENCE_BITS = 16L;

    // worker编号偏移量
    private static final long WORKER_SHIFT = SEQUENCE_BITS;

    // 时间偏移量
    private static final long TIMESTAMP_SHIFT = SEQUENCE_BITS + WORKER_BITS;

    // 序号掩码
    private static final long SEQUENCE_MASK = -1L ^ (-1L << SEQUENCE_BITS);

    // 毫秒基线:2015-01-01 00:00:00
    private static final long BASE_TIMESTAMP = 1420041600000L;

    private final long workerId;
    private volatile long sequence = 0L;
    private volatile long lastTimestamp = -1L;

    /**
     * 从环境变量中获取worker编号,每个部署环境编号不能重复
     */
    public IdWorker() {
        this(Misc.parseLong(System.getProperty("app.workerId"), 0L));
    }

    /**
     * 每个部署环境编号不能重复
     * 
     * @param workerId Worker编号
     */
    public IdWorker(long workerId) {
        if (workerId > MAX_WORKER_ID || workerId < 0) {
            throw new IllegalArgumentException(String.format("Worker Id can't be greater than %d or less than 0",
                    MAX_WORKER_ID));
        }
        this.workerId = workerId;
    }

    /**
     * 获取下一个ID
     * 
     * @return
     */
    public synchronized long next() {
        long ts = System.currentTimeMillis();
        if (lastTimestamp == ts) {
            sequence = (sequence + 1) & SEQUENCE_MASK;

            // 当前毫秒的序号已经用完,取下一个毫秒
            if (sequence == 0) {
                ts = nextMillis(lastTimestamp);
            }
        } else {
            sequence = 0L;
        }

        if (ts < lastTimestamp) {
            throw new RuntimeException(String.format(
                    "Clock moved backwards. Refusing to generate id for %d millseconds", lastTimestamp - ts));
        }

        lastTimestamp = ts;
        return ((ts - BASE_TIMESTAMP) << TIMESTAMP_SHIFT) | (workerId << WORKER_SHIFT) | sequence;
    }

    // FIXME:当机器时间被调早时,会导致CPU过高。此处可以考虑进行阻塞
    private long nextMillis(final long lastTimestamp) {
        long ts = System.currentTimeMillis();
        while (ts <= lastTimestamp) {
            ts = System.currentTimeMillis();
        }
        return ts;
    }

}

 

import java.io.File;
import java.security.MessageDigest;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import com.assess.lang.AppException;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;

public final class TextUtil {
    public static final int NO_TRIM = 0;
    public static final int TRIM_TO_NULL = 1;
    public static final int TRIM_TO_BLANK = 2;

    /**
     * 创建文件目录时使用的质数,默认每个文件夹下使用
     */
    private static final int SEED = 8999;
    private static final char[] CHARS_DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
            .toCharArray();
    private static final char[] HEX_DIGITS = "0123456789ABCDEF".toCharArray();

    private TextUtil() {
    }

    /**
     * 将日期(时间)格式化成指定格式的字符串
     * 
     * @param date 日期(时间)对象
     * @param pattern 格式化模式
     * @return
     */
    public static String formatTime(Date date, String pattern) {
        return new SimpleDateFormat(pattern).format(date);
    }

    /**
     * 将日期(时间)字符串解析成日期时间对象
     * 
     * @param val 日期(时间)字符串
     * @param pattern 时间模式
     * @return 返回日期对象,如果解析失败,则返回null
     */
    public static Date parseTime(String val, String pattern) {
        try {
            return new SimpleDateFormat(pattern).parse(val);
        } catch (ParseException e) {
            return null;
        }
    }

    /**
     * 使用单个字符分割字符串
     * 
     * @param value
     * @param delim
     * @return
     */
    public static String[] split(String value, char delim) {
        return split(value, delim, TRIM_TO_BLANK);
    }

    /**
     * 使用单个字符分割字符串
     * 
     * @param value
     * @param delim
     * @param trimFlag Trim方式
     * @return
     */
    public static String[] split(String value, char delim, int trimFlag) {
        final int end = value.length();
        final List<String> res = new ArrayList<String>();

        int start = 0;
        for (int i = 0; i < end; i++) {
            if (value.charAt(i) == delim) {
                if (start == i) {
                    res.add("");
                } else {
                    res.add(value.substring(start, i));
                }
                start = i + 1;
            }
        }

        if (start == 0) {
            res.add(value);
        } else if (start != end) {
            res.add(value.substring(start, end));
        } else {
            for (int i = res.size() - 1; i >= 0; i--) {
                if (res.get(i).isEmpty()) {
                    res.remove(i);
                } else {
                    break;
                }
            }
        }

        String[] ret = res.toArray(new String[res.size()]);
        if (trimFlag > 0) {
            for (int i = 0; i < ret.length; ++i) {
                if (trimFlag == TRIM_TO_NULL) {
                    ret[i] = trimToNull(ret[i]);
                } else {
                    ret[i] = trimToEmpty(ret[i]);
                }
            }
        }
        return ret;
    }

    /**
     * 对字符串进行MD5编码后转为16进制字符串
     * 
     * @param src
     * @return
     */
    public static String md5(String src, String salt) {
        return toHexString(digest("MD5", src, salt));
    }

    /**
     * 对对象进行MD5编码后转为16进制字符串
     * 
     * @param src
     * @return
     */
    public static String md5(Object obj, String salt) {
        return toHexString(digest("MD5", toBytes(obj), salt));
    }

    /**
     * 对字符串进行SHA-256编码后转为16进制字符串
     * 
     * @param src
     * @return
     */
    public static String sha256(String src, String salt) {
        return toHexString(digest("SHA-256", src, salt));
    }

    /**
     * 对字符串进行SHA-256编码后转为16进制字符串
     * 
     * @param src
     * @return
     */
    public static byte[] bSha256(String src, String salt) {
        return digest("SHA-256", src, salt);
    }

    /**
     * 合并两个字节数组
     * 
     * @param x
     * @param y
     * @return
     */
    public static byte[] merge(byte[] x, byte[] y) {
        byte[] b = new byte[x.length + y.length];

        System.arraycopy(x, 0, b, 0, x.length);
        System.arraycopy(y, 0, b, x.length, y.length);

        return b;
    }

    /**
     * 转换字节数组为16进制字串
     * 
     * @param b 字节数组
     * @return 16进制字串
     */
    public static String toHexString(byte[] b) {
        StringBuilder buf = new StringBuilder(b.length * 2);
        int n = 0;
        for (int i = 0; i < b.length; i++) {
            n = b[i];
            if (n < 0) {
                n += 256;
            }
            buf.append(HEX_DIGITS[n >> 4]).append(HEX_DIGITS[n % 16]);
        }
        return buf.toString();
    }

    /**
     * 根据给定的key和seed,生成唯一的有效文件路径。 有效文件路径需要满足: 1、每个文件夹下不超过10000个文件; 2、可以根据文件路径和seed还原key
     * 
     * @param key 用来生成文件路径的一个唯一数值,一般为文件的ID
     * @param deep 生成文件路径的有效深度,实际生成的路径深度为deep+1
     * @return
     */
    public static String dir(long key) {
        return dir(key, 2, SEED);
    }

    /**
     * 根据给定的key和seed,生成唯一的有效文件路径。 有效文件路径需要满足: 1、每个文件夹下不超过10000个文件; 2、可以根据文件路径和seed还原key
     * 
     * @param key 用来生成文件路径的一个唯一数值,一般为文件的ID
     * @param deep 生成文件路径的有效深度,实际生成的路径深度为deep+1
     * @return
     */
    public static String dir(long key, int deep) {
        return dir(key, deep, SEED);
    }

    /**
     * 根据给定的key和seed,生成唯一的有效文件路径。 有效文件路径需要满足: 1、每个文件夹下不超过10000个文件; 2、可以根据文件路径和seed还原key
     * 
     * @param key 用来生成文件路径的一个唯一数值,一般为文件的ID
     * @param deep 生成文件路径的有效深度,实际生成的路径深度为deep+1
     * @param seed 文件夹最大数量,有效取值为小于10000的质数
     * @return
     */
    public static String dir(long key, int deep, long seed) {
        StringBuilder buf = new StringBuilder(32);
        for (int i = 0; (i < deep) && (key > 0); i++) {
            base62(buf, key % seed);
            buf.append(File.separatorChar);
            key = key / seed;
        }
        return buf.append(key).toString();
    }

    /**
     * 生成随机的字符串,字符串有效字符为数字和字母
     * 
     * @param length 字符串长度
     * @return
     */
    public static String salt(int length) {
        StringBuilder buf = new StringBuilder(length);

        for (int i = 0; i < length; i++) {
            buf.append(CHARS_DIGITS[(int) (Math.random() * CHARS_DIGITS.length)]);
        }

        return buf.toString();
    }

    public static boolean isBlank(CharSequence cs) {
        int strLen;
        if ((cs == null) || ((strLen = cs.length()) == 0)) {
            return true;
        }
        for (int i = 0; i < strLen; i++) {
            if (Character.isWhitespace(cs.charAt(i)) == false) {
                return false;
            }
        }
        return true;
    }

    public static boolean isBlank(CharSequence cs, int end) {
        int strLen;
        if ((cs == null) || ((strLen = cs.length()) == 0)) {
            return true;
        }
        if ((end > 0) && (end < strLen)) {
            strLen = end;
        }
        for (int i = 0; i < strLen; i++) {
            if (Character.isWhitespace(cs.charAt(i)) == false) {
                return false;
            }
        }
        return true;
    }

    public static boolean isNotBlank(CharSequence cs) {
        return !isBlank(cs);
    }

    public static boolean isEmpty(CharSequence cs) {
        return (cs == null) || (cs.length() == 0);
    }

    public static boolean startsWith(String s, char c) {
        if (s.length() == 0) {
            return false;
        }
        return s.charAt(0) == c;
    }

    public static boolean endsWith(String s, char c) {
        if (s.length() == 0) {
            return false;
        }
        return s.charAt(s.length() - 1) == c;
    }

    public static String trim(String cs) {
        return cs == null ? null : cs.trim();
    }

    public static String trimToNull(String cs) {
        String s = trim(cs);
        return isEmpty(s) ? null : s;
    }

    public static String trimToEmpty(String cs) {
        String s = trim(cs);
        return s == null ? "" : s;
    }

    public static String trimToFlag(String src, String flag) {
        int index = src.indexOf(flag);
        if (index == -1) {
            return src;
        }
        return src.substring(0, index);
    }

    public static Long toLong(Object o) {
        if (o instanceof Long) {
            return (Long) o;
        }
        if (o instanceof String) {
            return Misc.parseLong((String) o, 0L);
        }

        if (o instanceof Integer) {
            return ((Integer) o).longValue();
        }

        return null;
    }

    public static Integer toInteger(Object o) {
        if (o instanceof Long) {
            return ((Long) o).intValue();
        }

        if (o instanceof String) {
            return Misc.parseInt((String) o, 0);
        }

        if (o instanceof Integer) {
            return (Integer) o;
        }

        return null;
    }

    @SuppressWarnings("unchecked")
    public static List<Long> toLongList(Object o) {
        if (!(o instanceof List)) {
            return Collections.EMPTY_LIST;
        }
        List<Object> list = (List<Object>) o;
        List<Long> result = new ArrayList<Long>(list.size());
        for (Object e : list) {
            result.add(toLong(e));
        }
        return result;
    }

    @SuppressWarnings("unchecked")
    public static List<Integer> toIntegerList(Object o) {
        if (!(o instanceof List)) {
            return Collections.EMPTY_LIST;
        }
        List<Object> list = (List<Object>) o;
        List<Integer> result = new ArrayList<Integer>(list.size());
        for (Object e : list) {
            result.add(toInteger(e));
        }
        return result;
    }

    public static String like(String src) {
        return like(src, LikeType.ALL);
    }

    public static String like(String src, LikeType type) {
        src = trim(src);
        if (src == null) {
            return src;
        }

        if (type == LikeType.LEFT) {
            return "%" + src;
        }
        if (type == LikeType.RIGHT) {
            return src + "%";
        }
        return "%" + src + "%";
    }

    private static void base62(StringBuilder buf, long val) {
        while (val > 0) {
            buf.append(CHARS_DIGITS[(int) (val % 62)]);
            val /= 62;
        }
    }

    private static byte[] digest(String algorithm, String src, String salt) {
        return digest(algorithm, src.getBytes(), salt);
    }

    private static byte[] digest(String algorithm, byte[] bytes, String salt) {

        try {
            if ((salt != null) && (salt.length() > 0)) {
                bytes = merge(bytes, salt.getBytes());
            }
            bytes = MessageDigest.getInstance(algorithm).digest(bytes);
        } catch (Exception e) {
            // 忽略异常
        }

        return bytes;
    }

    public static byte[] toBytes(Object obj) {
        try {
            Output output = new Output(new byte[2048], -1);
            new Kryo().writeObject(output, obj);
            output.flush();
            return output.toBytes();
        } catch (Exception e) {
            throw new AppException("Serialize Object failed", e);
        }
    }

    public static <T> T readBytes(byte[] bytes, Class<T> clazz) {
        if (bytes == null) {
            return null;
        }
        try {
            return new Kryo().readObject(new Input(bytes, 0, bytes.length), clazz);
        } catch (Exception e) {
            return null;
        }
    }

    public static byte[] int2Bytes(int num) {
        byte[] byteNum = new byte[4];
        for (int ix = 0; ix < 4; ++ix) {
            int offset = 32 - (ix + 1) * 8;
            byteNum[ix] = (byte) ((num >> offset) & 0xff);
        }
        return byteNum;
    }

    public static int bytes2Int(byte[] byteNum) {
        int num = 0;
        for (int ix = 0; ix < 4; ++ix) {
            num <<= 8;
            num |= (byteNum[ix] & 0xff);
        }
        return num;
    }

    public static byte[] long2Bytes(long num) {
        byte[] byteNum = new byte[8];
        for (int ix = 0; ix < 8; ++ix) {
            int offset = 64 - (ix + 1) * 8;
            byteNum[ix] = (byte) ((num >> offset) & 0xff);
        }
        return byteNum;
    }

    public static long bytes2Long(byte[] byteNum) {
        long num = 0;
        for (int ix = 0; ix < 8; ++ix) {
            num <<= 8;
            num |= (byteNum[ix] & 0xff);
        }
        return num;
    }

    public static enum LikeType {
        LEFT, RIGHT, ALL
    }
}

 

public final class Misc {
    private Misc() {
    }

    /**
     * 判断集合是否为null或空
     * 
     * @param c
     * @return
     */
    public static boolean isEmpty(Collection<?> c) {
        return ((c == null) || (c.size() == 0));
    }

    /**
     * 将字符串按','分割后存入Set
     * 
     * @param s
     * @return
     */
    public static Set<String> asSet(String s) {
        if ((s == null) || (s.trim().length() == 0)) {
            return null;
        }

        String[] parts = TextUtil.split(s, ',');
        Set<String> set = new HashSet<String>(parts.length);
        for (String part : parts) {
            String trimmed = part.trim();
            if (trimmed.length() > 0) {
                set.add(trimmed);
            }
        }
        return set;
    }

    /**
     * 生成上传文件的临时保存路径,并使用UUID对上传文件重命名。
     *
     * @param dir 临时文件保存的目录。使用系统绝对路径,一般使用"
     * @param suffix 文件名后缀
     * @param max 最大重试次数
     * @return 创建成功时返回文件的绝对路径,创建失败时返回null
     */
    public static File randomFile(String dir, String suffix, int max, boolean create) throws IOException {
        File p = new File(dir, TextUtil.formatTime(new Date(), "yyyyMMdd"));
        if (p.exists() || p.mkdirs()) {
            for (int i = 0; i < max; ++i) {
                File f = new File(p, TextUtil.salt(8) + suffix);
                if (!f.exists()) {
                    if (create && f.createNewFile()) {
                        return f;
                    }
                }
            }
        }

        return null;
    }

    /**
     * 安全地将字符串解析成整型
     * 
     * @param s 字符串
     * @param defaultValue 字符串为空(包括null)或解析失败时返回默认值
     * @return
     */
    public static int parseInt(String s, int defaultValue) {
        if ((s != null) && (s.length() > 0)) {
            try {
                return Integer.parseInt(s);
            } catch (NumberFormatException e) {
                // 忽略异常
            }
        }

        return defaultValue;
    }

    /**
     * 安全地将字符串解析成长整型
     * 
     * @param s 字符串
     * @param defaultValue 字符串为空(包括null)或解析失败时返回默认值
     * @return
     */
    public static long parseLong(String s, long defaultValue) {
        if ((s != null) && (s.length() > 0)) {
            try {
                return Long.parseLong(s);
            } catch (NumberFormatException e) {
                // 忽略异常
            }
        }

        return defaultValue;
    }

    /**
     * 获取远程客户端的IP地址
     * 
     * @param request
     * @return 没有找到ip时返回null
     */
    public static String parseIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Real-IP");
        if (TextUtil.isNotBlank(ip) && !"unknown".equalsIgnoreCase(ip)) {
            return ip;
        }

        ip = request.getHeader("X-Forwarded-For");
        if (!TextUtil.isBlank(ip)) {
            for (String value : TextUtil.split(ip, ',', TextUtil.TRIM_TO_NULL)) {
                if (value != null) {
                    if ("unknown".equalsIgnoreCase(ip)) {
                        break;
                    }
                    return value;
                }
            }
        }

        return request.getRemoteAddr();
    }

}

 

分享到:
评论

相关推荐

    C#根据时间产生ID编号

    ### C#根据时间产生ID编号 在软件开发中,经常需要为每一笔数据或记录生成唯一的标识符(ID)。在某些场景下,基于时间戳来生成ID是一种常见且有效的方法。这种方式不仅简单易行,还能确保大部分情况下ID的唯一性。...

    大批量产生id算法

    大批量插入数据时,高并发时,可避免id的重复且速度快

    CC2541的T1口产生PWM波型.doc

    在本文中,我们将深入探讨如何利用T1定时器来产生ID读卡头所需的125kHz载波PWM信号,并且重点讨论占空比的可调性。 首先,初始化T1定时器是生成PWM的关键步骤。在`PWM_Init`函数中,我们看到P0.7引脚被配置为输出,...

    LeadBBS数据库损坏导致帖子表ID编号重复修复程序

    证状: 部分LeadBBS数据库,产生数据库错误,导致主键丢失(字段名ID),并产生ID号相同的重复数据. 作用: 此程序即用来删除ID号相同的重复帖子数据. 副作用...

    SnowflakeIdWorker.java

    * * Twitter_Snowflake ... * * SnowFlake的优点是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由数据中心ID和机器ID作区分),并且效率较高,经测试,SnowFlake每秒能够产生26万ID左右。

    分布式ID生成,雪花算法生成唯一ID工具类

    分布式ID生成,雪花算法生成唯一ID工具类。...整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由数据中心ID和机器ID作区分),并且效率较高,经测试,SnowFlake每秒能够产生26万ID左右

    Java课程设计-图书管理系统.zip

    n 功能 4:产生ID n 功能分析:根据角色产生相应的ID n 功能 5:出版社序号 n 功能分析:根据序号分配对应的出版社 n 功能 6:出版社年份序号 n 功能分析:根据序号分配对应的出版年份 n 功能 7:借书 n 功能...

    多服务器游戏单点登陆设计思路 .

    3. 玩家程序连接游戏服务器,产生 ID2。 4. 游戏服务器和登陆服务器联系,ID2 和 ID1 互相认识。 为了保证信息安全,我们需要加密传送的信息。可以采用 DES 方式对信息进行加密和解密,而 DES 的密钥可以通过 RSA ...

    如何实现Oracle自增,序列,触发器都有

    如果ID字段已有值,则触发器会确保序列值至少等于这个值,以避免未来插入的数据产生ID冲突。 这种结合使用序列和触发器的方法是Oracle中一种常见的主键自增实现方式。它不仅确保了主键的唯一性和连续性,还大大提高...

    js 递归json树实现根据子id查父id的方法分析

    最近做了一个类似用js实现思维导图的功能,作为思维导图,一定会有树状结构的数据产生,在操作里面的节点时会经常需要查找节点 的父节点及父节点。 对于未知层级的树状数据,用for循环是无法实现的,因为不知道要...

    HookdiskID 硬盘ID修改硬盘物理id修改器

    此外,修改后的ID可能会与软件许可证产生冲突,甚至引发系统不稳定。 总的来说,HookdiskID是一个强大的工具,能够帮助用户解决特定场景下的硬盘ID问题,但同时也需要谨慎使用,以避免不必要的麻烦。在实际应用中,...

    device-id-changer

    例如,一些应用可能因为识别到IMEI变化而拒绝服务,或者在你试图恢复备份时产生冲突。此外,某些运营商和手机制造商可能会对IMEI的更改有严格的限制,甚至可能会封锁非法修改IMEI的设备。因此,除非有充分的理由,...

    ID_READ_ID卡的读取_ID卡读取_

    ID卡读取的过程中,读卡器发出特定频率的电磁波,当ID卡进入这个场强范围内时,其内部的线圈会感应到电磁波并产生电流,驱动芯片工作。芯片接收到信号后,将卡上的数据编码并通过反向电磁场回传给读卡器。读卡器接收...

    Oracle字符集id,16位id以及name

    ID ID(Hex) Name ID ID(Hex) Name ID ID(Hex) Name 1 0001 US7ASCII 2 0002 WE8DEC 3 0003 WE8HP 4 0004 US8PC437 5 0005 WE8EBCDIC37 6 0006 WE8EBCDIC500 7 0007 WE8EBCDIC1140 8 0008 WE8EBCDIC285 9 0009

    电路与模拟电子第三章.ppt

    - **N沟道耗尽型MOSFET**:即使在uGS=0时,由于预先存在的反型层,已经存在沟道,施加uDS即可产生iD。栅源电压uGS的改变会调整沟道宽度,从而影响iD。 - **P沟道MOSFET**:其工作原理与N沟道MOSFET类似,但导电...

    Acct-Session-idAcct-Session-id

    在深入探讨"Acct-Session-id"这一概念之前,我们首先需要理解其在IT网络管理与计费系统中的核心作用。"Acct-Session-id",即会计会话标识符,是RADIUS(Remote Authentication Dial In User Service)协议中一个关键...

    (源码)基于Spring Boot和RabbitMQ的商城高并发抢单系统.zip

    使用雪花算法生成全局唯一订单编号,确保在高并发场景下不会产生ID碰撞。 2. 分布式锁 通过Redis、Redisson和Zookeeper实现分布式锁,解决高并发场景下的数据一致性问题。 3. 消息队列 使用RabbitMQ实现消息的...

    边界网关协议BGP实践课(12)-Originator-ID属性

    Originator ID由RR产生,使用的Router ID的值标识路由的始发者,用于防止集群内产生路由环路。 当一条路由第一次被RR反射的时候,RR将Originator ID属性加入这条路由,标识这条路由的发起路由器。如果一条路由中已经...

    matlab利用idinput函数产生m序列.docx

    idinput 函数的基本语法为:`u = idinput(N,type,band,levels)`,其中 `N` 表示产生的序列的长度,`type` 指定产生信号的类型,`band` 指定信号的频率成分,`levels` 指定输入的水平。 对于不同类型的信号,idinput ...

    java自动生成id策略

    在上述代码中,`generateId`方法是线程安全的,因为使用了`synchronized`关键字,防止多线程并发访问时产生的数据不一致问题。`ThreadLocalRandom`被用来在每个线程内部生成随机数,它比`Random`更快且更适合多线程...

Global site tag (gtag.js) - Google Analytics