60 lines
2.7 KiB
Java
60 lines
2.7 KiB
Java
package com.baiyue.lastleg.service;
|
|
|
|
import net.sourceforge.pinyin4j.PinyinHelper;
|
|
import org.springframework.jdbc.core.JdbcTemplate;
|
|
import org.springframework.stereotype.Component;
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
import java.time.Instant;
|
|
import java.time.ZoneId;
|
|
import java.time.format.DateTimeFormatter;
|
|
import java.util.Locale;
|
|
|
|
/** Allocates suffix-free document numbers across all service instances. */
|
|
@Component
|
|
public class CompactBusinessNumberService {
|
|
private static final ZoneId ZONE = ZoneId.of("Asia/Shanghai");
|
|
private static final DateTimeFormatter FORMAT = DateTimeFormatter.ofPattern("yyMMddHHmmss", Locale.ROOT).withZone(ZONE);
|
|
private final JdbcTemplate jdbc;
|
|
private final ReturnOrderReferenceResolver customers;
|
|
|
|
public CompactBusinessNumberService(JdbcTemplate jdbc, ReturnOrderReferenceResolver customers) {
|
|
this.jdbc = jdbc;
|
|
this.customers = customers;
|
|
}
|
|
|
|
@Transactional
|
|
public String next(String prefix, String customerId) {
|
|
return allocate(prefix, initials(customers.customerName(customerId)), Instant.now());
|
|
}
|
|
|
|
String allocate(String prefix, String initials, Instant now) {
|
|
String key = prefix + "-" + initials;
|
|
long seconds = now.getEpochSecond();
|
|
// The row lock serializes identical prefixes/initials even across customers and JVMs.
|
|
jdbc.update("INSERT INTO ll_compact_number_clock(number_key,last_second) VALUES(?,LAST_INSERT_ID(?)) "
|
|
+ "ON DUPLICATE KEY UPDATE last_second=LAST_INSERT_ID(GREATEST(last_second+1,?))", key, seconds, seconds);
|
|
Long allocated = jdbc.queryForObject("SELECT LAST_INSERT_ID()", Long.class);
|
|
if (allocated == null || allocated < seconds) throw new IllegalStateException("业务编号生成失败");
|
|
return key + "-" + FORMAT.format(Instant.ofEpochSecond(allocated));
|
|
}
|
|
|
|
static String initials(String name) {
|
|
if (name == null || name.isBlank()) return "KH";
|
|
StringBuilder result = new StringBuilder();
|
|
boolean latinWord = false;
|
|
for (char c : name.trim().toCharArray()) {
|
|
if (result.length() >= 4) break;
|
|
if (Character.UnicodeScript.of(c) == Character.UnicodeScript.HAN) {
|
|
String[] pinyin = PinyinHelper.toHanyuPinyinStringArray(c);
|
|
if (pinyin != null && pinyin.length > 0) result.append(Character.toUpperCase(pinyin[0].charAt(0)));
|
|
latinWord = false;
|
|
} else if (c < 128 && Character.isLetterOrDigit(c)) {
|
|
if (!latinWord) result.append(Character.toUpperCase(c));
|
|
latinWord = true;
|
|
} else latinWord = false;
|
|
}
|
|
return result.isEmpty() ? "KH" : result.toString();
|
|
}
|
|
}
|