| | |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | |
| | | /** |
| | | * 报销单附件文件名规范校验(2026-10-15)。 |
| | | * 报销单附件文件名规范校验(2026-11-03 调整)。 |
| | | * |
| | | * <p>业务口径(业务方确认): |
| | | * <p>业务口径: |
| | | * <ol> |
| | | * <li>必须包含中文(至少 1 个汉字)——"为方便查验附件,请用中文规范命名附件!"</li> |
| | | * <li>去掉扩展名后的主干,按字符数计算不能超过 20 个字——"为方便查验附件,附件名字长度不能超过20个字!"</li> |
| | | * <li>允许文件名不含中文;含中文/纯英文/数字均可</li> |
| | | * <li>去掉扩展名后的主干,按字符数计算不能超过 20 个字</li> |
| | | * <li>不能包含空格及 {@code / \ : * ? " < > | # %} 等特殊字符</li> |
| | | * <li>同一明细行内不能重名(比较时忽略扩展名大小写与首尾空格)</li> |
| | | * <li>只校验新上传/新保存的附件;历史附件由 existingNames 放行</li> |
| | | * </ol> |
| | | * |
| | | * <p>与前端 {@code opo-web/src/utils/fileNameCheck.js} <b>同口径</b>: |
| | |
| | | /** 主干(去扩展名)最大字符数 */ |
| | | public static final int MAX_MAIN_LENGTH = 20; |
| | | |
| | | public static final String MSG_NO_CHINESE = "为方便查验附件,请用中文规范命名附件!"; |
| | | public static final String MSG_EMPTY_NAME = "为方便查验附件,附件名不能为空!"; |
| | | public static final String MSG_TOO_LONG = "为方便查验附件,附件名字长度不能超过20个字!"; |
| | | public static final String MSG_ILLEGAL = "为方便查验附件,附件名不能包含空格及 / \\ : * ? \" < > | # % 等特殊字符!"; |
| | | public static final String MSG_DUPLICATE = "为方便查验附件,同一行内不能有重名的附件!"; |
| | | /** 附件项里取不到任何文件名(既没有 name 也没有 fileName)时的提示 */ |
| | | public static final String MSG_NO_NAME = "为方便查验附件,附件必须带文件名,请重新上传!"; |
| | | |
| | | /** 汉字 */ |
| | | private static final Pattern CHINESE = Pattern.compile("[\\u4e00-\\u9fa5]"); |
| | | |
| | | /** 非法字符:空格(含各类空白)+ / \ : * ? " < > | # % */ |
| | | private static final Pattern ILLEGAL = Pattern.compile("[\\s/\\\\:*?\"<>|#%]"); |
| | |
| | | public static String checkName(String fileName) { |
| | | String name = fileName == null ? "" : fileName.trim(); |
| | | if (name.isEmpty()) { |
| | | return MSG_NO_CHINESE; |
| | | return MSG_EMPTY_NAME; |
| | | } |
| | | if (ILLEGAL.matcher(name).find()) { |
| | | return MSG_ILLEGAL; |
| | | } |
| | | String main = mainName(name); |
| | | if (!CHINESE.matcher(main).find()) { |
| | | return MSG_NO_CHINESE; |
| | | } |
| | | // 不再强制要求中文;含中文、纯英文、数字均可 |
| | | // 按字符数计(码点计数:中文/字母/数字/全角各计 1) |
| | | if (main.codePointCount(0, main.length()) > MAX_MAIN_LENGTH) { |
| | | return MSG_TOO_LONG; |