import org.apache.commons.lang3.StringUtils;

/**
 * @author : zanglikun
 * @date : 2025/11/3 10:21
 * @desc : 分省其他信息枚举
 * 下文信息已脱敏
 */
public enum ProvinceMisc {
    // 掩码值、 描述、 数值、 分省ID
    // 掩码值 格式是:1 << X 其中X从0递增,按照业务叠加即可。
    WGS(1 << 0, "W公司", 111),
    CHAO_GAO_YA(1 << 1, "超高压", 222),
    GUANG_DONG(1 << 2, "广东", 333),
    GUANG_XI(1 << 3, "广西", 444),
    YUN_NAN(1 << 4, "云南", 555),
    GUI_ZHOU(1 << 5, "贵州", 666),
    HAI_NAN(1 << 6, "海南", 777),
    SHEN_ZHEN(1 << 7, "深圳", 888);

    // 基础信息
    private final int mask;
    private final String desc;
    private final int value;

    ProvinceMisc(int mask, String desc, int value) {
        this.mask = mask;
        this.desc = desc;
        this.value = value;
    }

    public int getMask() {
        return mask;
    }

    public String getDesc() {
        return desc;
    }

    public int getValue() {
        return value;
    }

    public static ProvinceMisc fromValue(int value) {
        for (ProvinceMisc misc : ProvinceMisc.values()) {
            if (misc.value == value) {
                return misc;
            }
        }
        return null;
    }

    public static ProvinceMisc fromProvinceName(String desc) {
        for (ProvinceMisc misc : ProvinceMisc.values()) {
            if (StringUtils.equals(misc.desc, desc)) {
                return misc;
            }
        }
        return null;
    }
}
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author : zanglikun
 * @date : 2025/11/3 10:12
 * @desc : 位运算工具类。采用位运算实现对多个指标的组合查询和管理。
 * <a href="https://www.zanglikun.com/12441.html#%e5%88%a9%e7%94%a8%e4%bd%8d%e8%bf%90%e7%ae%97%e8%a1%a8%e7%a4%ba%e7%8a%b6%e6%80%81">查看类似说明</a>
 */
@Slf4j
public class ProvinceMiscUtils {


    /**
     * 判断是否包含某个指标
     *
     * @param provinceMisc 指标组合值(掩码值)- 由多个指标的掩码按位或组合而成
     *                     示例:0x1F (31) 表示包含多个指标
     * @param province     要检查的指标对象 - ProvinceMisc 枚举值
     *                     示例:ProvinceMisc.ADD_COUNT
     * @return true 表示该指标已包含;false 表示未包含
     * 原理:通过按位与操作判断是否存在
     */
    public static boolean hasProvince(int provinceMisc, ProvinceMisc province) {
        return (provinceMisc & province.getMask()) != 0;
    }

    /**
     * 添加一个指标
     *
     * @param provinceMisc 当前指标组合值(掩码值)
     * @param province     要添加的指标 - ProvinceMisc 枚举值
     * @return 新的指标组合值(掩码值)
     * 原理:通过按位或操作合并掩码
     */
    public static int addProvince(int provinceMisc, ProvinceMisc province) {
        return provinceMisc | province.getMask();
    }

    /**
     * 移除一个指标
     *
     * @param provinceMisc 当前指标组合值(掩码值)
     * @param province     要移除的指标 - ProvinceMisc 枚举值
     * @return 新的指标组合值(掩码值),该指标已被移除
     * 原理:通过按位与非操作清除特定掩码位
     */
    public static int removeProvince(int provinceMisc, ProvinceMisc province) {
        return provinceMisc & ~province.getMask();
    }

    /**
     * 批量添加指标,得到结果是新的值
     *
     * @param provinceMisc 初始指标组合值(掩码值)默认是0
     * @param provinces    可变长参数 - 多个要添加的指标
     *                     示例:addProvinces(0, ADD_COUNT, UPDATE_COUNT, DELETE_COUNT)
     * @return 最终的指标组合值(掩码值)
     */
    public static int addProvinces(int provinceMisc, ProvinceMisc... provinces) {
        for (ProvinceMisc province : provinces) {
            provinceMisc = addProvince(provinceMisc, province);
        }
        return provinceMisc;
    }

    /**
     * 批量添加指标,得到结果是新的值
     *
     * @param provinceMisc 初始指标组合值(掩码值)默认是0
     * @param provinceList 多个要添加的指标列表
     *                     示例:addProvinces(0, Lists.newArrayList("1","2"))
     * @return 最终的指标组合值(掩码值)
     */
    public static int addProvinces(int provinceMisc, List<ProvinceMisc> provinceList) {
        for (ProvinceMisc province : provinceList) {
            provinceMisc = addProvince(provinceMisc, province);
        }
        return provinceMisc;
    }

    /**
     * 批量移除指标
     *
     * @param provinceMisc 初始指标组合值(掩码值)
     * @param provinces    可变长参数 - 多个要移除的指标
     * @return 最终的指标组合值(掩码值)
     */
    public static int removeProvinces(int provinceMisc, ProvinceMisc... provinces) {
        for (ProvinceMisc province : provinces) {
            provinceMisc = removeProvince(provinceMisc, province);
        }
        return provinceMisc;
    }

    /**
     * 批量移除指标,得到结果是新的值
     *
     * @param provinceMisc 初始指标组合值(掩码值)
     * @param provinceList 多个要添加的指标列表
     *                     示例:addProvinces(0, Lists.newArrayList("1","2"))
     * @return 最终的指标组合值(掩码值)
     */
    public static int removeProvinces(int provinceMisc, List<ProvinceMisc> provinceList) {
        for (ProvinceMisc province : provinceList) {
            provinceMisc = removeProvince(provinceMisc, province);
        }
        return provinceMisc;
    }

    /**
     * 获取所有包含的指标列表
     *
     * @param provinceMisc 指标组合值(掩码值)- 由多个指标按位或组成
     *                     示例:31 (0x1F) 可能包含 ADD_COUNT、UPDATE_COUNT 等
     * @return 该掩码值包含的所有指标枚举对象列表
     * 示例返回:[ADD_COUNT, UPDATE_COUNT, DELETE_COUNT]
     */
    public static List<ProvinceMisc> getIncludedProvinces(int provinceMisc) {
        List<ProvinceMisc> list = new ArrayList<>();
        for (ProvinceMisc province : ProvinceMisc.values()) {
            if (hasProvince(provinceMisc, province)) {
                list.add(province);
            }
        }
        return list;
    }

    /**
     * 获取所有包含的指标描述
     *
     * @param provinceMisc 指标组合值(掩码值)
     *                     示例:0x1F (31)
     * @return 包含的所有指标的描述文本列表
     * 示例返回:["新增数量", "更新数量", "删除数量"]
     */
    public static List<String> getProvinceDescs(int provinceMisc) {
        return getIncludedProvinces(provinceMisc)
                .stream()
                .map(ProvinceMisc::getDesc)
                .collect(Collectors.toList());
    }

    /**
     * 获取所有包含的指标值(原始值 0-4)
     *
     * @param provinceMisc 指标组合值(掩码值)
     *                     掩码值与指标值的映射关系:
     *                     - 指标值(0-4):ProvinceMisc 枚举中的原始编号
     *                     - 掩码值:2^指标值,用于位运算
     *                     示例:指标值为 0 时,掩码值为 2^0=1
     * @return 该掩码值包含的所有指标的原始值列表
     * 示例返回:[0, 1, 2, 3, 4]
     */
    public static List<Integer> getProvinceValues(int provinceMisc) {
        return getIncludedProvinces(provinceMisc)
                .stream()
                .map(ProvinceMisc::getValue)
                .collect(Collectors.toList());
    }

    /**
     * 清空所有指标
     *
     * @param provinceMisc 当前指标组合值(掩码值)- 不使用此参数
     * @return 0 表示无指标
     */
    public static int clearAllProvinces(int provinceMisc) {
        return 0;
    }

    /**
     * 检查是否为空(没有任何指标)
     *
     * @param provinceMisc 指标组合值(掩码值)
     * @return true 表示为空(值为0);false 表示存在指标
     */
    public static boolean isEmpty(int provinceMisc) {
        return provinceMisc == 0;
    }

    /**
     * 获取所有可能的指标组合(包含空集)
     *
     * @return 所有有效的掩码值组合列表
     * 示例:如果有 3 个指标,返回 8 种组合
     * [0, 1, 2, 3, 4, 5, 6, 7] 对应所有的组合方式
     * 原理:2^n 种组合,其中 n 为指标总数
     */
    public static List<Integer> getAllCombinations() {
        int maxMask = 0;
        for (ProvinceMisc province : ProvinceMisc.values()) {
            maxMask |= province.getMask();
        }

        List<Integer> combinations = new ArrayList<>();
        // 从 0 到 maxMask,所有可能的组合都会出现
        for (int i = 0; i <= maxMask; i++) {
            // 验证该组合是否有效(只包含已定义的指标)
            if ((i & maxMask) == i) {
                combinations.add(i);
            }
        }
        return combinations;
    }

    /**
     * 解析指标,得到执行哪些方法!
     *
     * @param dbConfigProvinceMisc 传入的指标组合值(掩码值)- 从数据库查询出来
     *                             示例:31 (0x1F) 表示需要执行多个指标对应的方法
     *                             掩码值说明:
     * @throws IllegalArgumentException 当指标为空时抛出异常
     */
    private static void parseForPrintInfo(int dbConfigProvinceMisc) {

        // 验证和解析指标
        List<ProvinceMisc> provinces =
                ProvinceMiscUtils.getIncludedProvinces(dbConfigProvinceMisc);

        if (provinces.isEmpty()) {
            throw new IllegalArgumentException("请至少选择一个指标");
        }

        // 获取指标描述用于日志
        List<String> descs = ProvinceMiscUtils.getProvinceDescs(dbConfigProvinceMisc);
        log.info("查询条件, 指标: {}", descs);
    }


    /**
     * 根据 指定匹配的字段 字段转换为 枚举对象列表
     *
     * @param someValue       一些值的列表
     * @param objectExtractor 目标对象的提取函数 比如:ProvinceMisc::getName
     * @return 分省列表
     */
    public static List<ProvinceMisc> convertToProvinceList(List<String> someValue, Function<ProvinceMisc, String> objectExtractor) {
        if (CollectionUtils.isEmpty(someValue)) {
            return new ArrayList<>();
        }
        List<ProvinceMisc> result = new ArrayList<>();
        for (String value : someValue) {
            for (ProvinceMisc province : ProvinceMisc.values()) {
                String objValue = objectExtractor.apply(province);
                if (objValue.equals(value)) {
                    result.add(province);
                    break;
                }
            }
        }
        return result;
    }


    /**
     * 根据 前端传递的值 + 以及值对应的字段 转换为掩码值。主要是用于SQL的多条件查询使用
     *
     * @param someValue       一些值的列表
     * @param objectExtractor 目标对象的提取函数 比如:ProvinceMisc::getName
     *                        <p>
     *                        场景1 查询包含所有选中条件的记录
     *                        SELECT * FROM your_table
     *                        WHERE (province_misc & :mask) = :mask
     *                        <p>
     *                        场景2 查询包含任意一个选中条件的记录
     *                        SELECT * FROM your_table
     *                        WHERE (province_misc & :mask) != 0
     * @return SQL条件的值
     */
    public static Integer convertMultiConditionQuerySqlValue(List<Integer> someValue, Function<ProvinceMisc, Integer> objectExtractor) {
        int mask = 0;
        for (Integer value : someValue) {
            for (ProvinceMisc province : ProvinceMisc.values()) {
                Integer objValue = objectExtractor.apply(province);
                if (objValue.equals(value)) {
                    mask = addProvince(mask, province);
                    break;
                }
            }
        }
        return mask;
    }

    /**
     * 反向解析,将掩码值(数据库存储),解析为明文内容
     *
     * @param mask            一些值的列表
     * @param objectExtractor 目标对象的提取函数 比如:ProvinceMisc::getName
     * @return 明文内容列表
     */
    public static List<String> convertMaskToReadableStr(Integer mask, Function<ProvinceMisc, String> objectExtractor) {
        if (Objects.isNull(mask)) {
            return new ArrayList<>();
        }
        List<ProvinceMisc> includedProvinces = getIncludedProvinces(mask);
        return includedProvinces.stream().map(objectExtractor::apply).collect(Collectors.toList());
    }

    /**
     * main 方法 - 演示和测试 ProvinceMiscUtils 的各项功能
     */
    public static void main(String[] args) {
        // 示例:添加和检查指标
        List<Integer> provinceIds = Arrays.asList(111, 222);
        Integer mask = convertMultiConditionQuerySqlValue(provinceIds, ProvinceMisc::getValue);
        System.out.println("通过组织Id,得到掩码值: " + mask);

        System.out.println("通过掩码值,解析得到其代表的组织: " + convertMaskToReadableStr(mask, ProvinceMisc::getDesc));

        System.out.println("如果你是查询都包含这些组织的记录,可以使用SQL条件: WHERE 1 = 1 AND (province_misc & " + mask + ") = " + mask);
        System.out.println("如果你是查询包含任意一个组织的记录,可以使用SQL条件: WHERE 1 = 1 AND (province_misc & " + mask + ") != 0");

    }
}
特殊说明:
上述文章均是作者实际操作后产出。烦请各位,请勿直接盗用!转载记得标注原文链接:www.zanglikun.com
第三方平台不会及时更新本文最新内容。如果发现本文资料不全,可访问本人的Java博客搜索:标题关键字。以获取最新全部资料 ❤

免责声明:
本站文章旨在总结学习互联网技术过程中的经验与见解。任何人不得将其用于违法或违规活动!所有违规内容均由个人自行承担,与作者无关。