起因

某店等号大屏

朋友在点饮品时候,看到等号的大屏发现门店的单号是和门店的产品售卖情况强相关的,根据单号就可以看到一个门店当日的营业额情况。这样的单号生成方式和早起网站用户ID自增生成一样,虽然企业在外宣传自己有xx亿用户,但注册一个新用户看一下用户ID就完全暴露了。

按朋友的思路写的一个单号生成器

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import lombok.SneakyThrows;

/**
 * 按分秒生成票据,每秒生成9个,只能获取当前时间的票据
 *
 * @author p_x_c
 */
public class TicketGenerator {
    private static final int MAX_TICKETS_PER_SECOND = 9;
    private static final int TIMEOUT_SECONDS = 5;
    private final BlockingQueue<String> ticketQueue = new ArrayBlockingQueue<>(MAX_TICKETS_PER_SECOND);
    private final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("mmss");

    public TicketGenerator() {
        Thread generatorThread = new Thread(() -> {
            while (true) {
                try {
                    LocalDateTime now = LocalDateTime.now();
                    String timePrefix = now.format(FORMATTER);
                    for (int i = 1; i <= MAX_TICKETS_PER_SECOND; i++) {
                        String ticket = String.format("%s%01d", timePrefix, i);
                        ticketQueue.put(ticket);
                    }
                    // Sleep for one second before generating new tickets
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Thread.currentThread()
                          .interrupt();
                    break;
                }
            }
        });
        generatorThread.setDaemon(true);
        generatorThread.start();
    }

    @SneakyThrows
    public static void main(String[] args) {
        TicketGenerator ticketGenerator = new TicketGenerator();

        // Example usage
        for (int i = 0; i < 20; i++) {
            String ticket = ticketGenerator.getTicket();
            System.out.println("Got ticket: " + ticket);
            Thread.sleep(10); // Simulate some delay between requests
        }
    }

    @SneakyThrows
    public String getTicket() {
        LocalDateTime startTime = LocalDateTime.now();
        while (true) {
            String ticket = ticketQueue.poll(1, TimeUnit.SECONDS);
            if (ticket == null) {
                if (LocalDateTime.now()
                                 .isAfter(startTime.plusSeconds(TIMEOUT_SECONDS))) {
                    return "-1"; // Return -1 if timeout
                }
                continue;
            }

            // Check if the ticket matches the current time
            String currentPrefix = LocalDateTime.now()
                                                .format(FORMATTER);
            if (ticket.startsWith(currentPrefix)) {
                return ticket;
            }
        }
    }
}