{"record":{"id":"9a5c72bd172d4169","repo":"dromara/Sa-Token","slug":"id-id","errorCode":null,"errorMessage":"设备id或用户id不能为空","messagePattern":"设备id或用户id不能为空","errorType":"validation","errorClass":"RuntimeException","httpStatus":null,"severity":"warning","filePath":"sa-token-demo/sa-token-demo-device-lock/src/main/java/com/pj/util/DeviceLockCheckUtil.java","lineNumber":20,"sourceCode":"\nimport cn.dev33.satoken.SaManager;\nimport cn.dev33.satoken.util.SaFoxUtil;\n\n/**\n * 设备锁操作工具类\n * @author click33\n * @since 2025/3/5\n */\npublic class DeviceLockCheckUtil {\n\n    /**\n     * 保存设备id与用户id的映射关系\n     * @param deviceId /\n     * @param userId /\n     */\n    public static void setDeviceIdToUserId(String deviceId, long userId) {\n        if(SaFoxUtil.isEmpty(deviceId) || SaFoxUtil.isEmpty(userId)) {\n            throw new RuntimeException(\"设备id或用户id不能为空\");\n        }\n        SaManager.getSaTokenDao().set(saveKeyPrefix() + deviceId, String.valueOf(userId), 1200);\n    }\n\n    /**\n     * 返回设备id绑定的用户id\n     * @param deviceId /\n     */\n    public static long getUserIdByDeviceId(String deviceId) {\n        String userIdStr = SaManager.getSaTokenDao().get(saveKeyPrefix() + deviceId);\n        if(userIdStr == null) {\n            throw new RuntimeException(\"此设备id目前未绑定任何用户\");\n        }\n        return Long.parseLong(userIdStr);\n    }\n\n    // 返回数据保存时使用的前缀\n    public static Object saveKeyPrefix() {","sourceCodeStart":2,"sourceCodeEnd":38,"githubUrl":"https://github.com/dromara/Sa-Token/blob/ac2c7f6e94a78573cf0bcb932dd8b04e68fad189/sa-token-demo/sa-token-demo-device-lock/src/main/java/com/pj/util/DeviceLockCheckUtil.java#L2-L38","documentation":"Demo utility in sa-token-demo-device-lock (device-binding example). setDeviceIdToUserId persists a deviceId -> userId mapping with a 1200-second TTL and requires both arguments to be non-empty; an empty deviceId (or the always-non-empty long check failing on userId==0, since SaFoxUtil.isEmpty(long) boxes to Long and only 0/empty triggers) throws RuntimeException. It is sample code, not part of the library.","triggerScenarios":"Calling DeviceLockCheckUtil.setDeviceIdToUserId(deviceId, userId) with deviceId null/empty/whitespace, or userId == 0 (SaFoxUtil.isEmpty treats boxed 0 as empty).","commonSituations":"Frontend not sending the device-id header/param so the controller passes null; using userId 0 as a sentinel; adapting the demo and keeping the isEmpty(long) guard which wrongly rejects id 0.","solutions":["Ensure the client submits a non-empty deviceId (usually a header set by the app/mini-program) before calling setDeviceIdToUserId","Guard the call: if (SaFoxUtil.isEmpty(deviceId) || userId <= 0) return error to the caller instead of throwing","If you adapted this code, change SaFoxUtil.isEmpty(userId) to userId <= 0 so legitimate id 0 is not rejected"],"exampleFix":"// before\nDeviceLockCheckUtil.setDeviceIdToUserId(requestDeviceId, userId); // null device id\n\n// after\nif (SaFoxUtil.isEmpty(requestDeviceId) || userId <= 0) {\n    throw new SaTokenException(\"请提交有效的设备id与用户id\");\n}\nDeviceLockCheckUtil.setDeviceIdToUserId(requestDeviceId, userId);","handlingStrategy":"validation","validationCode":"if (SaFoxUtil.isEmpty(deviceId) || userId <= 0) {\n    // return a 400 to the client; do not call setDeviceIdToUserId\n}","typeGuard":"public static boolean isValidDeviceBinding(String deviceId, long userId) {\n    return deviceId != null && !deviceId.trim().isEmpty() && userId > 0;\n}","tryCatchPattern":null,"preventionTips":["Require the client to send a device id (header) before binding","If you adapt this demo, replace SaFoxUtil.isEmpty(userId) with userId <= 0","Validate at the controller boundary, not inside the DAO util"],"tags":["sa-token","demo","device-lock","validation"],"backgroundTag":null,"analyzedSha":"ac2c7f6e94a78573cf0bcb932dd8b04e68fad189","analyzedAt":"2026-08-14T14:36:10.271Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}