From d99580f0c939a1b974f2fb3c2fd7449ac3e2f60a Mon Sep 17 00:00:00 2001 From: qingfeng1121 Date: Tue, 2 Dec 2025 14:55:30 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E7=99=BB=E5=BD=95):=20=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E7=99=BB=E5=BD=95=E5=8A=9F=E8=83=BD=E5=8F=8A?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加LoginController处理登录请求 - 实现UserLoginService登录逻辑,包括角色和权限验证 - 新增LoginRequest和LoginUser DTO - 在UsersService中添加登录方法 - 添加RoleInitializer初始化系统角色 - 更新项目结构文档 - 临时禁用Spring Security配置 --- doc/项目结构.md | 81 ++++++++++++++++++ .../qf/backend/config/RoleInitializer.java | 63 ++++++++++++++ .../backend/controller/LoginController.java | 33 +++++++ .../java/com/qf/backend/dto/LoginRequest.java | 24 ++++++ .../java/com/qf/backend/dto/LoginUser.java | 4 +- .../com/qf/backend/mapper/UsersMapper.java | 8 ++ .../com/qf/backend/service/UsersService.java | 12 ++- .../service/impl/UserLoginServiceImpl.java | 85 ++++++++++++++++--- .../service/impl/UsersRolesServiceImpl.java | 3 +- .../service/impl/UsersServiceImpl.java | 24 +++++- .../java/com/qf/backend/util/TimeUtils.java | 31 +++++++ src/main/resources/application.properties | 2 + 12 files changed, 351 insertions(+), 19 deletions(-) create mode 100644 doc/项目结构.md create mode 100644 src/main/java/com/qf/backend/config/RoleInitializer.java create mode 100644 src/main/java/com/qf/backend/controller/LoginController.java create mode 100644 src/main/java/com/qf/backend/dto/LoginRequest.java create mode 100644 src/main/java/com/qf/backend/util/TimeUtils.java diff --git a/doc/项目结构.md b/doc/项目结构.md new file mode 100644 index 0000000..cf6f183 --- /dev/null +++ b/doc/项目结构.md @@ -0,0 +1,81 @@ +e:\TaoTaoWang\backend\ +├── pom.xml # Maven依赖配置 +├── src/main/java/com/taotaowang/ +│ ├── TaotaoWangApplication.java # 应用主启动类 +│ ├── config/ # 配置类 +│ │ ├── SecurityConfig.java # 安全配置 +│ │ ├── MyBatisPlusConfig.java # MyBatis-Plus配置 +│ │ ├── RedisConfig.java # Redis配置 +│ │ ├── SwaggerConfig.java # Swagger文档配置 +│ │ └── WebConfig.java # Web配置 +│ ├── controller/ # 控制器层 +│ │ ├── AuthController.java # 认证相关接口 +│ │ ├── UserController.java # 用户管理接口 +│ │ ├── RoleController.java # 角色管理接口 +│ │ ├── PermissionController.java # 权限管理接口 +│ │ ├── ProductController.java # 商品管理接口 +│ │ ├── OrderController.java # 订单管理接口 +│ │ ├── ShopController.java # 店铺管理接口 +│ │ └── MarketingController.java # 营销活动接口 +│ ├── service/ # 业务层 +│ │ ├── impl/ # 业务实现类 +│ │ │ ├── AuthServiceImpl.java +│ │ │ ├── UserServiceImpl.java +│ │ │ ├── RoleServiceImpl.java +│ │ │ ├── PermissionServiceImpl.java +│ │ │ ├── ProductServiceImpl.java +│ │ │ ├── OrderServiceImpl.java +│ │ │ ├── ShopServiceImpl.java +│ │ │ └── MarketingServiceImpl.java +│ │ ├── AuthService.java # 认证服务接口 +│ │ ├── UserService.java # 用户服务接口 +│ │ ├── RoleService.java # 角色服务接口 +│ │ ├── PermissionService.java # 权限服务接口 +│ │ ├── ProductService.java # 商品服务接口 +│ │ ├── OrderService.java # 订单服务接口 +│ │ ├── ShopService.java # 店铺服务接口 +│ │ └── MarketingService.java # 营销服务接口 +│ ├── mapper/ # 数据访问层 +│ │ ├── UserMapper.java +│ │ ├── RoleMapper.java +│ │ ├── PermissionMapper.java +│ │ ├── ProductMapper.java +│ │ ├── OrderMapper.java +│ │ └── ShopMapper.java +│ ├── entity/ # 实体层 +│ │ ├── User.java +│ │ ├── Role.java +│ │ ├── Permission.java +│ │ ├── Product.java +│ │ ├── Order.java +│ │ ├── Shop.java +│ │ └── Marketing.java +│ ├── dto/ # 数据传输对象 +│ │ ├── request/ # 请求DTO +│ │ │ ├── LoginRequest.java +│ │ │ ├── RegisterRequest.java +│ │ │ ├── ProductRequest.java +│ │ │ └── OrderRequest.java +│ │ └── response/ # 响应DTO +│ │ ├── LoginResponse.java +│ │ ├── UserResponse.java +│ │ ├── ProductResponse.java +│ │ └── OrderResponse.java +│ ├── exception/ # 异常处理 +│ │ ├── GlobalExceptionHandler.java # 全局异常处理器 +│ │ ├── BusinessException.java # 业务异常 +│ │ └── ErrorCode.java # 错误码定义 +│ ├── util/ # 工具类 +│ │ ├── JwtUtil.java # JWT工具 +│ │ ├── SecurityUtil.java # 安全工具 +│ │ └── ResponseUtil.java # 响应工具 +│ └── interceptor/ # 拦截器 +│ ├── JwtInterceptor.java # JWT拦截器 +│ └── LogInterceptor.java # 日志拦截器 +└── src/main/resources/ + ├── application.yml # 主配置文件 + ├── application-dev.yml # 开发环境配置 + ├── application-test.yml # 测试环境配置 + ├── application-prod.yml # 生产环境配置 + ├── mapper/ # MyBatis映射文件 + └── static/ # 静态资源目录 \ No newline at end of file diff --git a/src/main/java/com/qf/backend/config/RoleInitializer.java b/src/main/java/com/qf/backend/config/RoleInitializer.java new file mode 100644 index 0000000..57e9f90 --- /dev/null +++ b/src/main/java/com/qf/backend/config/RoleInitializer.java @@ -0,0 +1,63 @@ +package com.qf.backend.config; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.qf.backend.entity.Roles; +import com.qf.backend.service.RolesService; + +import jakarta.annotation.PostConstruct; + +/** + * 角色初始化配置类,用于在系统启动时创建内置角色 + * @author 30803 + */ +@Component +public class RoleInitializer { + private static final Logger logger = LoggerFactory.getLogger(RoleInitializer.class); + + @Autowired + private RolesService rolesService; + + /** + * 系统启动时初始化内置角色 + */ + @PostConstruct + public void initRoles() { + logger.info("开始初始化内置角色..."); + + // 定义内置角色信息 + String[][] roleInfos = { + {"用户", "默认用户角色", "0"}, // roleType: 0-默认用户 + {"店主", "店铺管理员角色", "1"}, // roleType: 1-店主 + {"管理员", "系统管理员角色", "2"} // roleType: 2-管理员 + }; + + for (String[] roleInfo : roleInfos) { + String roleName = roleInfo[0]; + String description = roleInfo[1]; + Integer roleType = Integer.parseInt(roleInfo[2]); + + // 检查角色是否已存在 + Roles existingRole = rolesService.getOne(new QueryWrapper().eq("role_name", roleName)); + if (existingRole == null) { + // 创建新角色 + Roles role = new Roles(); + role.setRoleName(roleName); + role.setDescription(description); + role.setRoleType(roleType); + role.setStatus(1); // 启用状态 + + rolesService.save(role); + logger.info("成功创建内置角色: {}", roleName); + } else { + logger.info("内置角色 {} 已存在,跳过创建", roleName); + } + } + + logger.info("内置角色初始化完成"); + } +} \ No newline at end of file diff --git a/src/main/java/com/qf/backend/controller/LoginController.java b/src/main/java/com/qf/backend/controller/LoginController.java new file mode 100644 index 0000000..89e39d0 --- /dev/null +++ b/src/main/java/com/qf/backend/controller/LoginController.java @@ -0,0 +1,33 @@ +/* + * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license + * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template + */ + +package com.qf.backend.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.qf.backend.common.Result; +import com.qf.backend.dto.LoginRequest; +import com.qf.backend.dto.LoginUser; +import com.qf.backend.service.UserLoginService; +/** + * + * @author 30803 + */ +@RestController +@RequestMapping("/api/login") +public class LoginController { + @Autowired + private UserLoginService userLoginService; + + @PostMapping("/login") + public Result login(@RequestBody LoginRequest loginRequest) { + return userLoginService.login(loginRequest.getUsername(), loginRequest.getPassword()); + } + +} diff --git a/src/main/java/com/qf/backend/dto/LoginRequest.java b/src/main/java/com/qf/backend/dto/LoginRequest.java new file mode 100644 index 0000000..7f44d92 --- /dev/null +++ b/src/main/java/com/qf/backend/dto/LoginRequest.java @@ -0,0 +1,24 @@ +/* + * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license + * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template + */ + +package com.qf.backend.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + + + +/** + * 登录请求参数 + * @author 30803 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class LoginRequest { + private String username; + private String password; +} diff --git a/src/main/java/com/qf/backend/dto/LoginUser.java b/src/main/java/com/qf/backend/dto/LoginUser.java index dd63d6e..243e1b1 100644 --- a/src/main/java/com/qf/backend/dto/LoginUser.java +++ b/src/main/java/com/qf/backend/dto/LoginUser.java @@ -15,7 +15,8 @@ import lombok.NoArgsConstructor; * @param id 用户ID * @param username 用户名 * @param password 密码 - * @param roles 权限 + * @param roles 角色列表 + * @param permissions 权限列表 * @author 30803 */ @Data @@ -27,4 +28,5 @@ public class LoginUser { private String username; private String password; private List roles; + private List permissions; } diff --git a/src/main/java/com/qf/backend/mapper/UsersMapper.java b/src/main/java/com/qf/backend/mapper/UsersMapper.java index fac2744..b2faa7f 100644 --- a/src/main/java/com/qf/backend/mapper/UsersMapper.java +++ b/src/main/java/com/qf/backend/mapper/UsersMapper.java @@ -11,6 +11,14 @@ import com.qf.backend.entity.Users; * 用户基本信息表 Mapper 接口 */ public interface UsersMapper extends BaseMapper { + /** + * 登录 + * @param username 用户名 + * @param password 密码 + * @return 用户对象 + */ + @Select("select * from users where username = #{username} and password = #{password}") + Users login(String username, String password); /** * 根据用户名查询用户 * @param username 用户名 diff --git a/src/main/java/com/qf/backend/service/UsersService.java b/src/main/java/com/qf/backend/service/UsersService.java index 45b8e99..85f2411 100644 --- a/src/main/java/com/qf/backend/service/UsersService.java +++ b/src/main/java/com/qf/backend/service/UsersService.java @@ -1,11 +1,11 @@ package com.qf.backend.service; +import java.util.List; + import com.baomidou.mybatisplus.extension.service.IService; import com.qf.backend.common.Result; import com.qf.backend.entity.Users; -import java.util.List; - /** * 用户服务接口 */ @@ -25,6 +25,14 @@ public interface UsersService extends IService { */ Result getUserByEmail(String email); + /** + * 登录 + * @param username 用户名 + * @param password 密码 + * @return 用户信息 + */ + Result login(String username, String password); + /** * 创建用户 * @param users 用户信息 diff --git a/src/main/java/com/qf/backend/service/impl/UserLoginServiceImpl.java b/src/main/java/com/qf/backend/service/impl/UserLoginServiceImpl.java index 32cde08..7189ef6 100644 --- a/src/main/java/com/qf/backend/service/impl/UserLoginServiceImpl.java +++ b/src/main/java/com/qf/backend/service/impl/UserLoginServiceImpl.java @@ -4,6 +4,12 @@ */ package com.qf.backend.service.impl; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -12,13 +18,21 @@ import org.springframework.stereotype.Service; import com.qf.backend.common.Result; import com.qf.backend.common.ResultUtils; import com.qf.backend.dto.LoginUser; +import com.qf.backend.entity.Permissions; +import com.qf.backend.entity.Roles; +import com.qf.backend.entity.UserRoles; import com.qf.backend.entity.Users; import com.qf.backend.exception.ErrorCode; +import com.qf.backend.service.PermissionsService; +import com.qf.backend.service.RolePermissionsService; +import com.qf.backend.service.RolesService; import com.qf.backend.service.UserLoginService; +import com.qf.backend.service.UserRolesService; import com.qf.backend.service.UsersService; import com.qf.backend.util.ValidateUtil; + /** * * @author 30803 @@ -28,7 +42,14 @@ public class UserLoginServiceImpl implements UserLoginService { private Logger logger = LoggerFactory.getLogger(UserLoginServiceImpl.class); @Autowired private UsersService usersServiceImpl; - + @Autowired + private UserRolesService userRolesServiceImpl; + @Autowired + private RolesService rolesServiceImpl; + @Autowired + private RolePermissionsService rolePermissionsServiceImpl; + @Autowired + private PermissionsService permissionsServiceImpl; /** * 用户登录 * @param username 用户名 @@ -39,26 +60,62 @@ public class UserLoginServiceImpl implements UserLoginService { public Result login(String username, String password) { logger.info("用户登录,用户名:{}", username); // 1. 校验用户名和密码是否为空 + try{ if (ValidateUtil.isEmpty(username) || ValidateUtil.isEmpty(password)) { - return ResultUtils.fail(ErrorCode.PARAM_ERROR, "用户名或密码不能为空"); - } - // 2. 校验用户名是否存在 - Users user = usersServiceImpl.getUserByUsername(username).getData(); - if (user == null) { - return ResultUtils.fail(ErrorCode.USER_NOT_FOUND, "用户名不存在"); - } - // 3. 校验密码是否正确 + throw new IllegalArgumentException("用户名或密码不能为空"); + } // 加密密码 String encryptedPassword = ValidateUtil.encryptPassword(password); - if (!user.getPassword().equals(encryptedPassword)) { - return ResultUtils.fail(ErrorCode.PASSWORD_ERROR, "密码错误"); + // 2. 登录 + Result result = usersServiceImpl.login(username, encryptedPassword); + if (result == null || result.getData() == null) { + throw new IllegalArgumentException("用户名不存在或密码错误"); } - // 4. 登录成功,返回登录用户信息 + + Users user = result.getData(); + // 3. 获取用户角色 + Result> userRolesResult = userRolesServiceImpl.getUserRolesByUserId(user.getId()); + if (userRolesResult == null || userRolesResult.getData() == null) { + throw new IllegalArgumentException("获取用户角色失败"); + } + + List userRoles = userRolesResult.getData(); + Set roleNames = new HashSet<>(); + Set roleIds = new HashSet<>(); + + // 4. 获取角色名称和角色ID + for (UserRoles ur : userRoles) { + Roles role = rolesServiceImpl.getById(ur.getRoleId()); + if (role != null) { + roleNames.add(role.getRoleName()); + roleIds.add(role.getId()); + } + } + + // 5. 获取用户权限 + Set permissionCodes = new HashSet<>(); + for (Long roleId : roleIds) { + List permissionIds = rolePermissionsServiceImpl.listPermissionIdsByRoleId(roleId); + for (Long permissionId : permissionIds) { + Permissions permission = permissionsServiceImpl.getById(permissionId); + if (permission != null) { + permissionCodes.add(permission.getPermissionCode()); + } + } + } + + // 6. 构建LoginUser对象 LoginUser loginUser = new LoginUser(); - // loginUser.setUserId(user.getUserId()); + loginUser.setId(user.getId()); loginUser.setUsername(user.getUsername()); - // loginUser.setRoles(userRolesServiceImpl.findRolesByUserId(user.getUserId())); + loginUser.setRoles(new ArrayList<>(roleNames)); + loginUser.setPermissions(new ArrayList<>(permissionCodes)); + return ResultUtils.success(loginUser); + } catch (Exception e) { + logger.error("用户登录失败,用户名:{}", username, e); + return ResultUtils.fail(ErrorCode.SYSTEM_ERROR, e.getMessage()); + } } } diff --git a/src/main/java/com/qf/backend/service/impl/UsersRolesServiceImpl.java b/src/main/java/com/qf/backend/service/impl/UsersRolesServiceImpl.java index 3a1cdd4..ca47dda 100644 --- a/src/main/java/com/qf/backend/service/impl/UsersRolesServiceImpl.java +++ b/src/main/java/com/qf/backend/service/impl/UsersRolesServiceImpl.java @@ -8,6 +8,7 @@ package com.qf.backend.service.impl; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; @@ -18,7 +19,6 @@ import com.qf.backend.exception.BusinessException; import com.qf.backend.exception.ErrorCode; import com.qf.backend.mapper.UserRolesMapper; import com.qf.backend.service.UserRolesService; -import com.qf.backend.util.ValidateUtil; @@ -27,6 +27,7 @@ import com.qf.backend.util.ValidateUtil; * * @author 30803 */ +@Service public class UsersRolesServiceImpl extends ServiceImpl implements UserRolesService { @Autowired private UserRolesMapper userRolesMapper; diff --git a/src/main/java/com/qf/backend/service/impl/UsersServiceImpl.java b/src/main/java/com/qf/backend/service/impl/UsersServiceImpl.java index 87c9274..95a2b17 100644 --- a/src/main/java/com/qf/backend/service/impl/UsersServiceImpl.java +++ b/src/main/java/com/qf/backend/service/impl/UsersServiceImpl.java @@ -79,7 +79,29 @@ public class UsersServiceImpl extends ServiceImpl implements throw new BusinessException(ErrorCode.DATABASE_ERROR, "查询用户失败: " + e.getMessage(), e); } } - + // 登录 + @Override + public Result login(String username, String password) { + logger.info("登录: 用户名 = {}", username); + try { + if (ValidateUtil.isEmpty(username) || ValidateUtil.isEmpty(password)) { + throw new BusinessException(ErrorCode.INVALID_PARAM, "用户名或密码不能为空"); + } + + // 校验用户名是否存在 + Users user = usersMapper.login(username, password); + if (user == null) { + throw new BusinessException(ErrorCode.USER_NOT_FOUND, "用户名不存在或密码错误"); + } + + return ResultUtils.success(user); + } catch (BusinessException e) { + throw e; + } catch (Exception e) { + logger.error("登录失败: {}", e.getMessage(), e); + throw new BusinessException(ErrorCode.DATABASE_ERROR, "登录失败: " + e.getMessage(), e); + } + } //创建用户 @Override public Result createUser(Users users) { diff --git a/src/main/java/com/qf/backend/util/TimeUtils.java b/src/main/java/com/qf/backend/util/TimeUtils.java new file mode 100644 index 0000000..95c223b --- /dev/null +++ b/src/main/java/com/qf/backend/util/TimeUtils.java @@ -0,0 +1,31 @@ +/* + * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license + * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template + */ + +package com.qf.backend.util; + +import java.sql.Date; +import java.text.SimpleDateFormat; + +/** + * 时间工具类 + * @author 30803 + */ +public class TimeUtils { + /** + * 获取当前时间戳 + * @return 当前时间戳 + */ + public static long getCurrentTimestamp() { + return System.currentTimeMillis(); + } + /** + * 将时间戳转换为时间字符串 + * @param timestamp 时间戳 + * @return 时间字符串 + */ + public static String timestampToString(long timestamp) { + return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(timestamp)); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 7128b9f..857b5e2 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -5,3 +5,5 @@ spring.datasource.url=jdbc:mysql://localhost:3306/TaoTaoWang?useUnicode=true&cha spring.datasource.username=root spring.datasource.password=123456 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver +# 暂时关闭Spring Security +spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration