有个需求,根据日期来生成一个自增长编号,格式:2019090400001。
思路是使用AtomicInteger
原子操作类,好处就是不会出现重复,在多线程操作环境下优势尤为明显,可以自行研究一下。
下面是实现代码
public class TextUtil { public static ConcurrentHashMap<String, AtomicInteger> ID = new ConcurrentHashMap<>(); private static String timeFlag; static { //初始值 ID.put("num", new AtomicInteger(1)); } /** * 生成案件编号,格式:2019082300001 * @return */ public static String getCaseNo() { String now = DateUtil.getDate(); if (!now.equals(timeFlag)) { timeFlag = now; ID.get("num").getAndSet(1); } int nextNum = ID.get("num").getAndIncrement(); String str = String.format("%05d", nextNum); now += str; return now; } public static void main(String[] args) { for (int i = 0; i < 20; i++) { System.out.println(getCaseNo()); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
测试结果
初步实现了功能,但是当项目重启后编号会重新开始计算。
这里考虑使用缓存机制把值存起来,项目重启时再次获取并赋值。
下面一个版本修改上述风险,使用文件存储,缺点就是增加了磁盘IO。
当然你可以使用更为高效的Redis
或者其它技术。
public class TextUtil { public static ConcurrentHashMap<String, AtomicInteger> ID = new ConcurrentHashMap<>(); private final static String file = TextUtil.class.getResource("").getPath() + "eventId.ini"; private static String timeFlag; static { //初始值 //程序启动时获取文件内容 String str = read(); int num = 1; if (StringUtils.isNotBlank(str)) { timeFlag = str.substring(0, 8);//最后更新日期,格式:yyyyMMdd String numStr = str.substring(8); num = Integer.parseInt(numStr); num++; } ID.put("num", new AtomicInteger(num)); } /** * 生成编号,格式:2019082300001 * * @return */ public static String getCaseNo() { String now = DateUtil.getDate(); if (!now.equals(timeFlag)) { timeFlag = now; ID.get("num").getAndSet(1); } int nextNum = ID.get("num").getAndIncrement(); store(nextNum + ""); String str = String.format("%05d", nextNum); now += str; store(now); return now; } //存数据 private static void store(String eventId) { //写入相应的文件 BufferedOutputStream out = null; try { out = new BufferedOutputStream(new FileOutputStream(file)); byte[] bytes = eventId.getBytes(); //写入文件 out.write(bytes, 0, bytes.length); //清缓存 out.flush(); out.close(); } catch (Exception e) { e.printStackTrace(); } finally { if (out != null) { try { //清缓存 out.flush(); out.close(); } catch (Exception e) { } } } } //读数据 private static String read() { String str = ""; //读取文件(缓存字节流) BufferedInputStream in = null; try { File f = new File(file); if (!f.exists()) { f.createNewFile(); } in = new BufferedInputStream(new FileInputStream(f)); //读取数据 //一次性取多少字节 byte[] bytes = new byte[32]; //接受读取的内容(n就代表的相关数据,只不过是数字的形式) int n = -1; //循环取出数据 while ((n = in.read(bytes, 0, bytes.length)) != -1) { //转换成字符串 str = new String(bytes, 0, n, "UTF-8"); } } catch (Exception e) { e.printStackTrace(); } finally { //关闭流 if (in != null) { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } } return str; } public static void main(String[] args) { for (int i = 0; i < 20; i++) { System.out.println(getCaseNo()); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
再次测试的时候就有连续性了