Просмотр исходного кода

提供一个统一流水号生成接口

ximinghao 7 месяцев назад
Родитель
Сommit
feaa300920

+ 41 - 0
src/main/java/com/skyversation/xjcy/controller/SerialNumberController.java

@@ -0,0 +1,41 @@
+package com.skyversation.xjcy.controller;
+
+import com.skyversation.xjcy.service.SerialNumberGenerator;
+import com.skyversation.xjcy.util.MessageManage;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.MediaType;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.util.Arrays;
+
+
+@Slf4j
+@Validated
+@RestController
+@RequestMapping()
+public class SerialNumberController {
+    @Resource
+    SerialNumberGenerator serialNumberGenerator;
+
+    @RequestMapping(value = "/serialNumber", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+    public String serialNumber(HttpServletRequest request) {
+        try {
+            String prefix = request.getParameter("prefix");
+            SerialNumberGenerator.Prefix p = null;
+            try {
+                p = SerialNumberGenerator.Prefix.valueOf(prefix);
+            } catch (IllegalArgumentException e) {
+                return MessageManage.getInstance().getResultContent(-1,"可用前缀: " + Arrays.toString(SerialNumberGenerator.Prefix.values()),"可用前缀: " + Arrays.toString(SerialNumberGenerator.Prefix.values()));
+            }
+            String value = serialNumberGenerator.generate(p);
+            return MessageManage.getInstance().getResultContent(200, value, "成功生成流水号");
+        } catch (Exception e) {
+            return MessageManage.getInstance().getResultContent(500, e.getMessage(), "未知错误");
+        }
+
+    }
+}

+ 26 - 0
src/main/java/com/skyversation/xjcy/service/DMSService.java

@@ -255,6 +255,32 @@ public class DMSService {
         return queryDmsList(new DMSRequest(), token, columId);
     }
 
+    public int getLargestCode(String token,String columId,String codeColumn,String today){
+        DMSRequest request = new DMSRequest();
+        request.addWhere(codeColumn,"2","%"+today+"%");
+        List<JSONObject> list = null;
+        try {
+            list = queryDmsList(request,token,columId);
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new RuntimeException("无法获取流水号:无法获取DMS中流水号对应的表。");
+        }
+        String pattern = ".*"+today;
+        int max = 0;
+        for (JSONObject jsonObject : list) {
+            try {
+                int code = Integer.parseInt(jsonObject.get(codeColumn).toString().replaceAll(pattern,""));
+                if (code > max) {
+                    max = code;
+                }
+            } catch (NumberFormatException e) {
+                e.printStackTrace();
+                throw new RuntimeException("无法获取流水号:出现了未预期的流水号");
+            }
+        }
+        return max;
+    }
+
     public <T extends FromJSON> List<T> query(String token, DMSQuery query, Class<T> clazz, LocalDate now) {
         if (query.getResultType() != clazz) {
             throw new RuntimeException("类型与枚举提供的类型不符,请确认枚举中的类型");

+ 180 - 0
src/main/java/com/skyversation/xjcy/service/SerialNumberGenerator.java

@@ -0,0 +1,180 @@
+package com.skyversation.xjcy.service;
+
+import lombok.Getter;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.Resource;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.EnumMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.ReentrantLock;
+
+@Service
+public class SerialNumberGenerator {
+    @Resource
+    DMSService dmsService;
+
+    // 前缀枚举定义(可根据需要扩展)
+    @Getter
+    public enum Prefix {
+        XS("XS", "1576", "c_clue_code"),
+        //PT("PT","" ,"" ) ,
+        ED("ED", "1587", "c_work_order_code"),
+        EP("EP", "1592", "c_product_code"),
+        PR("PR", "1591", "c_requirement_code");
+        private final String code;
+        private final String columId;
+        private final String codeColumn;
+
+        Prefix(String code, String columId, String codeColumn) {
+            this.code = code;
+            this.columId = columId;
+            this.codeColumn = codeColumn;
+        }
+
+    }
+
+    // 存储每个前缀的当前状态
+    private final Map<Prefix, SerialState> stateMap = new ConcurrentHashMap<>();
+    // 存储每个前缀的初始化状态
+    private final Map<Prefix, Boolean> initializedMap = new ConcurrentHashMap<>();
+    // 用于初始化时的同步锁
+    private final Map<Prefix, ReentrantLock> initLocks = new EnumMap<>(Prefix.class);
+
+    // 日期格式化器(线程安全)
+    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.BASIC_ISO_DATE;
+
+    public SerialNumberGenerator() {
+        // 为每个前缀初始化锁
+        for (Prefix prefix : Prefix.values()) {
+            initLocks.put(prefix, new ReentrantLock());
+        }
+    }
+
+    @PostConstruct
+    public void autoInit() {
+        String token;
+        try {
+            token = dmsService.loginForToken();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        for (Prefix prefix : Prefix.values()) {
+            try {
+                String today = currentDate();
+                int max = dmsService.getLargestCode(token, prefix.getColumId(), prefix.getCodeColumn(), today);
+                initPrefix(prefix, max+1 , today);
+            } catch (Exception e) {
+                System.out.println(prefix+"流水号初始化失败");
+                e.printStackTrace();
+            }
+        }
+    }
+
+    /**
+     * 生成流水号
+     *
+     * @param prefix 前缀枚举
+     * @return 生成的流水号字符串
+     * @throws IllegalStateException 如果前缀未初始化
+     */
+    public String generate(Prefix prefix) {
+        // 检查是否已初始化
+        if (!isInitialized(prefix)) {
+            throw new IllegalStateException("Prefix " + prefix + " not initialized. Call initPrefix() first.");
+        }
+
+        // 获取或创建当前状态
+        SerialState currentState = getOrCreateState(prefix);
+
+        // 原子递增并格式化
+        int nextSerial = currentState.counter.incrementAndGet();
+        if (nextSerial > 999) {
+            throw new IllegalStateException("Serial number overflow for prefix: " + prefix);
+        }
+
+        return prefix.getCode() + currentState.date + String.format("%03d", nextSerial);
+    }
+
+    /**
+     * 初始化指定前缀的流水号
+     *
+     * @param prefix       前缀枚举
+     * @param initialValue 初始值(1-999)
+     * @param today        初始化数据的时间
+     * @throws IllegalArgumentException 初始值不在有效范围
+     * @throws IllegalStateException    如果前缀已初始化
+     */
+    public void initPrefix(Prefix prefix, int initialValue, String today) {
+        if (initialValue < 1 || initialValue > 999) {
+            throw new IllegalArgumentException("Initial value must be between 1 and 999");
+        }
+
+        ReentrantLock lock = initLocks.get(prefix);
+        lock.lock();
+        try {
+            if (isInitialized(prefix)) {
+                throw new IllegalStateException("Prefix " + prefix + " already initialized");
+            }
+
+            stateMap.put(prefix, new SerialState(today, new AtomicInteger(initialValue - 1)));
+            initializedMap.put(prefix, true);
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * 检查前缀是否已初始化
+     */
+    public boolean isInitialized(Prefix prefix) {
+        return initializedMap.getOrDefault(prefix, false);
+    }
+
+    // 获取或创建当前状态(处理日期切换)
+    private SerialState getOrCreateState(Prefix prefix) {
+        String today = currentDate();
+        SerialState currentState = stateMap.get(prefix);
+
+        // 如果状态存在且日期匹配,直接返回
+        if (currentState != null && currentState.date.equals(today)) {
+            return currentState;
+        }
+
+        // 处理日期切换或状态不存在的情况
+        ReentrantLock lock = initLocks.get(prefix);
+        lock.lock();
+        try {
+            // 双重检查锁定模式
+            currentState = stateMap.get(prefix);
+            if (currentState == null || !currentState.date.equals(today)) {
+                // 创建新的状态(计数器从0开始)
+                currentState = new SerialState(today, new AtomicInteger(0));
+                stateMap.put(prefix, currentState);
+            }
+            return currentState;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    // 获取当前日期字符串(yyyyMMdd)
+    private String currentDate() {
+        return LocalDate.now().format(DATE_FORMATTER);
+    }
+
+    // 状态存储内部类
+    private static class SerialState {
+        final String date;        // 当前日期(yyyyMMdd)
+        final AtomicInteger counter; // 当前计数器值
+
+        SerialState(String date, AtomicInteger counter) {
+            this.date = date;
+            this.counter = counter;
+        }
+    }
+}