`

产生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编号C#根据时间产生ID编号C#根据时间产生ID编号

    大批量产生id算法

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

    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 功能...

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

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

    数据库设计规范化的五个要求.doc

    否则的话,很容易产生ID值不统一的情况。 另外,在数据库设计的时候,最好还能够加入行号。如在销售订单管理中,ID号是 用户不能够维护的。但是,行号用户就可以维护。如在销售订单的行中,用户可以通过 调整行号的...

    IdWorker(1).zip_ropejst_分布式自增长ID

    整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由datacenter和机器ID作区分)

    CC2541的T1口产生PWM波型.doc

    TI CC2541采用定时器T1产生的PWM波型,占空比可调,例子为产生ID读卡头载波125KH的PWM波型;

    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

    数据库设计参考规范.doc

    否则的话,很容易产生ID值不统一的情况。 另外,在数据库设计的时候,最好还能够加入行号。ID号是用户不能够维护的。但是 ,行号用户就可以维护。这是在实际应用程序设计中对ID列的一个有效补充。 要求四:数据库...

    MySQL数据库设计学习.pdf

    否则的话,很容易产生ID值不统一的情况。 另外,在数据库设计的时候,最好还能 够加入行号。如在销售订 单管理中,ID号是用户不能够维护的。但是,行号用户就可以维护。如 在销售订单的行中,用户可以通过调整行号的...

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

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

    java快速ID自增器

    id自增,适用于快速,频繁产生自增ID,在spring配置数据源即可

    随机id生成器

    ID生成器是指能产生不重复ID服务的程序,在后台开发过程中,尤其是分布式服务、微服务程序开发过程中,经常会用到,例如,为用户的每个请求产生一个唯一ID、为每个消息产生一个ID等等,ID生成器也是进行无状态服务...

    NewSid windows系统产生新的安全ID

    由于windows系统产生新的安全ID,在企业部署ghost操作系统后,需重新生成新的sid,否则集中管理可能会发生很多异常故障。

    go-id-builder ID生成器

    这是一个ID生成器,它可以提供通过高效的方式产生连续的唯一的ID值。在分库分表时可以提供非常有用的帮助。

    golang开发的ID生成器go-id-builder.zip

    go-id-builder这是一个使用golang开发的ID生成器,它可以提供通过高效的方式产生连续唯一的ID值。在分库分表时可以提供非常有用的帮助。为什么要做id生成器常常在数据库进行分库分表的需求处理时,需要给表产生一个...

Global site tag (gtag.js) - Google Analytics