# LoginUserUtil 工具类使用文档 ## 概述 `LoginUserUtil` 是一个用于在web端商户平台(`alien-store-platform`)中获取当前登录用户信息的工具类。它封装了从JWT Token中提取用户信息以及从数据库查询完整用户信息的常用方法。 --- ## 核心特性 - ✅ **静态方法**: 所有方法都是静态方法,可直接调用,无需实例化 - ✅ **自动注入**: 使用`@Autowired`自动注入`StoreUserMapper` - ✅ **异常处理**: 所有方法都包含完善的异常处理,确保不会抛出异常 - ✅ **日志记录**: 详细的日志记录,便于调试和问题排查 - ✅ **多种获取方式**: 支持从Token获取基本信息,或从数据库查询完整信息 --- ## 类结构 ```java @Slf4j @Component public class LoginUserUtil { // 核心方法 public static Integer getCurrentUserId() // 获取用户ID public static String getCurrentUserPhone() // 获取手机号 public static String getCurrentUserType() // 获取用户类型 public static JSONObject getCurrentUserInfo() // 获取Token中的用户信息 public static StoreUser getCurrentStoreUser() // 获取完整用户信息(数据库) public static StoreUser getCurrentStoreUserByPhone() // 根据手机号获取用户信息 // 辅助方法 public static boolean isCurrentUser(Integer userId) // 验证是否为当前用户 public static boolean isLogin() // 验证是否已登录 public static boolean isStorePlatformUser() // 验证是否为商户平台用户 // 便捷方法 public static Integer getCurrentStoreId() // 获取门店ID public static String getCurrentNickName() // 获取昵称 public static String getCurrentName() // 获取真实姓名 } ``` --- ## 方法详解 ### 1. getCurrentUserId() 获取当前登录用户的ID(从Token中获取,无需查询数据库) ```java /** * 获取当前登录用户的ID * @return 用户ID,如果未登录返回null */ public static Integer getCurrentUserId() ``` **使用示例**: ```java Integer userId = LoginUserUtil.getCurrentUserId(); if (userId != null) { System.out.println("当前用户ID: " + userId); } else { System.out.println("用户未登录"); } ``` **返回值**: - 成功: 返回用户ID(Integer) - 未登录: 返回`null` **性能**: ⚡ 快速(只解析Token,不查询数据库) --- ### 2. getCurrentUserPhone() 获取当前登录用户的手机号(从Token中获取) ```java /** * 获取当前登录用户的手机号 * @return 手机号,如果未登录返回null */ public static String getCurrentUserPhone() ``` **使用示例**: ```java String phone = LoginUserUtil.getCurrentUserPhone(); if (phone != null) { System.out.println("当前用户手机号: " + phone); } ``` **返回值**: - 成功: 返回手机号(String) - 未登录: 返回`null` **性能**: ⚡ 快速(只解析Token) --- ### 3. getCurrentUserType() 获取当前登录用户的用户类型(从Token中获取) ```java /** * 获取当前登录用户的用户类型 * @return 用户类型,如果未登录返回null */ public static String getCurrentUserType() ``` **使用示例**: ```java String userType = LoginUserUtil.getCurrentUserType(); if ("storePlatform".equals(userType)) { System.out.println("商户平台用户"); } ``` **返回值**: - 成功: 返回用户类型(String),如 `"storePlatform"` - 未登录: 返回`null` **性能**: ⚡ 快速(只解析Token) --- ### 4. getCurrentUserInfo() 获取当前登录用户的Token信息(JSONObject格式) ```java /** * 获取当前登录用户的Token信息(JSONObject格式) * @return 用户信息JSONObject,包含userId、phone、userType等字段 */ public static JSONObject getCurrentUserInfo() ``` **使用示例**: ```java JSONObject userInfo = LoginUserUtil.getCurrentUserInfo(); if (userInfo != null) { Integer userId = userInfo.getInteger("userId"); String phone = userInfo.getString("phone"); String userType = userInfo.getString("userType"); System.out.println("用户ID: " + userId); System.out.println("手机号: " + phone); System.out.println("用户类型: " + userType); } ``` **返回值**: - 成功: 返回包含用户信息的`JSONObject` - 未登录: 返回`null` **包含字段**: - `userId`: 用户ID - `phone`: 手机号 - `userType`: 用户类型 **性能**: ⚡ 快速(只解析Token) --- ### 5. getCurrentStoreUser() 获取当前登录用户的完整商户用户信息(从数据库查询) ```java /** * 获取当前登录用户的完整商户用户信息(从数据库查询) * @return StoreUser对象,如果未登录或查询失败返回null */ public static StoreUser getCurrentStoreUser() ``` **使用示例**: ```java StoreUser storeUser = LoginUserUtil.getCurrentStoreUser(); if (storeUser != null) { System.out.println("用户ID: " + storeUser.getId()); System.out.println("手机号: " + storeUser.getPhone()); System.out.println("昵称: " + storeUser.getNickName()); System.out.println("真实姓名: " + storeUser.getName()); System.out.println("门店ID: " + storeUser.getStoreId()); System.out.println("账户余额: " + storeUser.getMoney()); } ``` **返回值**: - 成功: 返回`StoreUser`对象(包含所有字段) - 未登录: 返回`null` - 查询失败: 返回`null` **性能**: 🐢 较慢(需要查询数据库) **注意**: - 适用于需要完整用户信息的场景 - 会产生数据库查询,建议在需要时才调用 --- ### 6. getCurrentStoreUserByPhone() 根据手机号获取商户用户信息(从数据库查询) ```java /** * 根据手机号获取商户用户信息 * @return StoreUser对象,如果未登录或查询失败返回null */ public static StoreUser getCurrentStoreUserByPhone() ``` **使用示例**: ```java StoreUser storeUser = LoginUserUtil.getCurrentStoreUserByPhone(); if (storeUser != null) { System.out.println("用户信息: " + storeUser); } ``` **返回值**: - 成功: 返回`StoreUser`对象 - 未登录: 返回`null` - 查询失败: 返回`null` **性能**: 🐢 较慢(需要查询数据库) **与 getCurrentStoreUser() 的区别**: - `getCurrentStoreUser()`: 根据用户ID查询(主键查询,更快) - `getCurrentStoreUserByPhone()`: 根据手机号查询(索引查询,稍慢) --- ### 7. isCurrentUser(Integer userId) 验证当前登录用户是否为指定用户 ```java /** * 验证当前登录用户是否为指定用户 * @param userId 要验证的用户ID * @return true-是当前用户, false-不是当前用户 */ public static boolean isCurrentUser(Integer userId) ``` **使用示例**: ```java Integer targetUserId = 12345; if (LoginUserUtil.isCurrentUser(targetUserId)) { System.out.println("是当前用户,允许操作"); } else { System.out.println("不是当前用户,拒绝操作"); } ``` **使用场景**: - 权限验证:确保用户只能修改自己的信息 - 安全检查:防止用户操作其他用户的数据 **返回值**: - `true`: 是当前登录用户 - `false`: 不是当前登录用户或未登录 --- ### 8. isLogin() 验证当前用户是否已登录 ```java /** * 验证当前用户是否已登录 * @return true-已登录, false-未登录 */ public static boolean isLogin() ``` **使用示例**: ```java if (LoginUserUtil.isLogin()) { System.out.println("用户已登录"); } else { System.out.println("用户未登录"); } ``` **返回值**: - `true`: 已登录 - `false`: 未登录 --- ### 9. isStorePlatformUser() 验证当前用户类型是否为web端商户平台 ```java /** * 验证当前用户类型是否为web端商户平台 * @return true-是商户平台用户, false-不是 */ public static boolean isStorePlatformUser() ``` **使用示例**: ```java if (LoginUserUtil.isStorePlatformUser()) { System.out.println("商户平台用户,允许访问"); } else { System.out.println("非商户平台用户,拒绝访问"); } ``` **返回值**: - `true`: 用户类型为 `storePlatform` - `false`: 用户类型不是 `storePlatform` 或未登录 --- ### 10. getCurrentStoreId() 获取当前登录用户的门店ID ```java /** * 获取当前登录用户的门店ID * @return 门店ID,如果未登录或用户无门店返回null */ public static Integer getCurrentStoreId() ``` **使用示例**: ```java Integer storeId = LoginUserUtil.getCurrentStoreId(); if (storeId != null) { System.out.println("当前用户的门店ID: " + storeId); } ``` **返回值**: - 成功: 返回门店ID(Integer) - 未登录: 返回`null` - 用户无门店: 返回`null` **性能**: 🐢 较慢(需要查询数据库) --- ### 11. getCurrentNickName() 获取当前登录用户的昵称 ```java /** * 获取当前登录用户的昵称 * @return 昵称,如果未登录返回null */ public static String getCurrentNickName() ``` **使用示例**: ```java String nickName = LoginUserUtil.getCurrentNickName(); if (nickName != null) { System.out.println("欢迎," + nickName); } ``` **返回值**: - 成功: 返回昵称(String) - 未登录: 返回`null` **性能**: 🐢 较慢(需要查询数据库) --- ### 12. getCurrentName() 获取当前登录用户的真实姓名 ```java /** * 获取当前登录用户的真实姓名 * @return 真实姓名,如果未登录返回null */ public static String getCurrentName() ``` **使用示例**: ```java String name = LoginUserUtil.getCurrentName(); if (name != null) { System.out.println("真实姓名: " + name); } ``` **返回值**: - 成功: 返回真实姓名(String) - 未登录: 返回`null` **性能**: 🐢 较慢(需要查询数据库) --- ## 实际应用场景 ### 场景1: 获取当前用户的基本信息 ```java @RestController @RequestMapping("/user") public class UserController { @GetMapping("/profile") public R getUserProfile() { // 获取当前登录用户的完整信息 StoreUser storeUser = LoginUserUtil.getCurrentStoreUser(); if (storeUser == null) { return R.fail("请先登录"); } return R.data(storeUser); } } ``` --- ### 场景2: 验证用户权限(只能操作自己的数据) ```java @Service public class StoreServiceImpl implements StoreService { @Override public boolean updateStore(Integer storeId, StoreInfo storeInfo) { // 获取当前用户的门店ID Integer currentStoreId = LoginUserUtil.getCurrentStoreId(); // 验证用户只能修改自己的门店信息 if (!storeId.equals(currentStoreId)) { throw new RuntimeException("您只能修改自己的门店信息"); } // 执行更新操作 return updateStoreInfo(storeInfo); } } ``` --- ### 场景3: 自动填充当前用户信息 ```java @Service public class OrderServiceImpl implements OrderService { @Override public boolean createOrder(Order order) { // 自动填充当前用户信息 Integer userId = LoginUserUtil.getCurrentUserId(); Integer storeId = LoginUserUtil.getCurrentStoreId(); order.setUserId(userId); order.setStoreId(storeId); order.setCreateTime(new Date()); return orderMapper.insert(order) > 0; } } ``` --- ### 场景4: 根据用户类型返回不同数据 ```java @Service public class DashboardServiceImpl implements DashboardService { @Override public JSONObject getDashboardData() { JSONObject result = new JSONObject(); // 验证用户类型 if (!LoginUserUtil.isStorePlatformUser()) { throw new RuntimeException("只有商户平台用户可以访问"); } // 获取用户信息 Integer storeId = LoginUserUtil.getCurrentStoreId(); // 查询仪表盘数据 result.put("todayIncome", getTodayIncome(storeId)); result.put("todayOrderCount", getTodayOrderCount(storeId)); return result; } } ``` --- ### 场景5: 日志记录(记录操作人) ```java @Service public class AuditLogServiceImpl implements AuditLogService { @Override public void logOperation(String action, String details) { AuditLog log = new AuditLog(); // 记录操作人信息 log.setUserId(LoginUserUtil.getCurrentUserId()); log.setUserPhone(LoginUserUtil.getCurrentUserPhone()); log.setUserName(LoginUserUtil.getCurrentName()); log.setAction(action); log.setDetails(details); log.setOperateTime(new Date()); auditLogMapper.insert(log); } } ``` --- ### 场景6: 条件查询(只查询当前用户的数据) ```java @Service public class OrderServiceImpl implements OrderService { @Override public List getMyOrders(Integer page, Integer size) { // 获取当前用户ID Integer userId = LoginUserUtil.getCurrentUserId(); if (userId == null) { throw new RuntimeException("请先登录"); } // 查询当前用户的订单 LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(Order::getUserId, userId) .orderByDesc(Order::getCreateTime); return orderMapper.selectPage(new Page<>(page, size), wrapper).getRecords(); } } ``` --- ### 场景7: 简化Controller代码 **之前的写法**: ```java @PostMapping("/updateProfile") public R updateProfile(@RequestBody StoreUser storeUser) { // 需要手动获取用户信息 JSONObject userInfo = JwtUtil.getCurrentUserInfo(); if (userInfo == null) { return R.fail("请先登录"); } Integer userId = userInfo.getInteger("userId"); storeUser.setId(userId); boolean success = storeUserService.updateById(storeUser); return success ? R.success("修改成功") : R.fail("修改失败"); } ``` **使用工具类后**: ```java @PostMapping("/updateProfile") public R updateProfile(@RequestBody StoreUser storeUser) { // 直接获取用户ID Integer userId = LoginUserUtil.getCurrentUserId(); if (userId == null) { return R.fail("请先登录"); } storeUser.setId(userId); boolean success = storeUserService.updateById(storeUser); return success ? R.success("修改成功") : R.fail("修改失败"); } ``` --- ## 性能对比 | 方法 | 性能 | 是否查询数据库 | 适用场景 | |------|------|---------------|----------| | `getCurrentUserId()` | ⚡⚡⚡ 极快 | ❌ 否 | 只需要用户ID | | `getCurrentUserPhone()` | ⚡⚡⚡ 极快 | ❌ 否 | 只需要手机号 | | `getCurrentUserType()` | ⚡⚡⚡ 极快 | ❌ 否 | 验证用户类型 | | `getCurrentUserInfo()` | ⚡⚡⚡ 极快 | ❌ 否 | 需要Token中的多个字段 | | `getCurrentStoreUser()` | 🐢 较慢 | ✅ 是 | 需要完整用户信息 | | `getCurrentStoreUserByPhone()` | 🐢 较慢 | ✅ 是 | 根据手机号查询 | | `getCurrentStoreId()` | 🐢 较慢 | ✅ 是 | 只需要门店ID | | `getCurrentNickName()` | 🐢 较慢 | ✅ 是 | 只需要昵称 | | `getCurrentName()` | 🐢 较慢 | ✅ 是 | 只需要真实姓名 | **优化建议**: - ✅ 优先使用不查询数据库的方法(`getCurrentUserId()`、`getCurrentUserPhone()`等) - ✅ 如果需要多个用户字段,使用`getCurrentStoreUser()`一次性获取,避免多次查询 - ✅ 不要在循环中调用需要查询数据库的方法 --- ## 注意事项 ### 1. 空值处理 所有方法在获取失败时都返回`null`,使用时需要判空: ```java Integer userId = LoginUserUtil.getCurrentUserId(); if (userId != null) { // 处理业务逻辑 } else { // 处理未登录情况 } ``` ### 2. 异常处理 工具类内部已处理所有异常,不会向外抛出异常,确保调用安全。 ### 3. 静态方法限制 由于使用静态方法,需要通过`@Autowired`注入`StoreUserMapper`到静态字段。这是通过`@Component`和setter方法实现的。 ### 4. 性能考虑 - **频繁调用**: 如果需要频繁获取用户信息,建议在Service层缓存 - **数据库查询**: 避免在循环中调用需要查询数据库的方法 ### 5. 线程安全 工具类是线程安全的,可以在多线程环境下使用。 --- ## 与 @LoginRequired 注解配合使用 `LoginUserUtil` 与 `@LoginRequired` 注解配合使用效果更佳: ```java @RestController @RequestMapping("/store") public class StoreController { @LoginRequired // AOP切面验证登录 @GetMapping("/myStore") public R getMyStore() { // 登录验证已通过,直接获取门店ID Integer storeId = LoginUserUtil.getCurrentStoreId(); StoreInfo storeInfo = storeService.getById(storeId); return R.data(storeInfo); } } ``` --- ## 配置要求 ### 1. Spring Bean注册 工具类使用`@Component`注解,需要被Spring扫描到: ```java @Component // 必须 public class LoginUserUtil { // ... } ``` ### 2. 包扫描配置 确保`LoginUserUtil`所在的包被Spring Boot扫描: ```java @SpringBootApplication @ComponentScan(basePackages = {"shop.alien.storeplatform"}) public class Application { // ... } ``` ### 3. Mapper依赖 确保`StoreUserMapper`已注册为Spring Bean: ```java @Mapper public interface StoreUserMapper extends BaseMapper { } ``` --- ## 常见问题 ### Q1: 为什么有时返回null? **原因**: 1. 用户未登录(Token不存在或无效) 2. Token已过期 3. 用户在数据库中不存在 4. 网络或数据库异常 **解决方案**: - 使用前先判断是否已登录:`LoginUserUtil.isLogin()` - 检查日志中的错误信息 --- ### Q2: 如何在非Controller层使用? **答案**: 工具类可以在任何Spring管理的Bean中使用: ```java @Service public class MyService { public void someMethod() { Integer userId = LoginUserUtil.getCurrentUserId(); // 使用userId } } ``` --- ### Q3: 性能是否有问题? **答案**: - Token解析方法(如`getCurrentUserId()`)性能很高,可以频繁调用 - 数据库查询方法(如`getCurrentStoreUser()`)性能较低,建议缓存结果 --- ### Q4: 如何缓存用户信息? **建议方案**: ```java @Service public class MyService { private StoreUser currentUser; public void processOrder() { // 第一次获取 if (currentUser == null) { currentUser = LoginUserUtil.getCurrentStoreUser(); } // 后续使用缓存的数据 Integer storeId = currentUser.getStoreId(); // ... } } ``` 或使用ThreadLocal缓存(适用于同一次请求)。 --- ## 更新日志 ### 2025-11-17 **新增工具类**: - ✅ 创建`LoginUserUtil`工具类 **核心功能**: - ✅ 获取当前登录用户ID、手机号、用户类型 - ✅ 获取Token中的用户信息(JSONObject) - ✅ 从数据库查询完整用户信息 - ✅ 验证用户登录状态 - ✅ 验证用户类型 - ✅ 验证是否为当前用户 - ✅ 获取门店ID、昵称、姓名等便捷方法 **技术特点**: - ✅ 静态方法,方便调用 - ✅ 完善的异常处理 - ✅ 详细的日志记录 - ✅ 支持多种获取方式 **开发人员**: ssk --- **文档版本**: v1.0 **最后更新**: 2025-11-17 **维护人员**: ssk