# hmallnew **Repository Path**: testing-category/hmallnew ## Basic Information - **Project Name**: hmallnew - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-05-18 - **Last Updated**: 2025-05-24 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 黑马商城项目 ## 项目概述 这是一个基于Spring Cloud微服务架构的电商项目,包含网关、用户服务、购物车服务、商品服务等多个微服务。 ## 服务架构 - **hm-gateway**: 网关服务 (端口: 8080) - **user-service**: 用户服务 (端口: 8084) - **cart-service**: 购物车服务 (端口: 8082) - **item-service**: 商品服务 (端口: 8081) - **trade-service**: 交易服务 (端口: 8083) - **pay-service**: 支付服务 (端口: 8085) ## 用户认证流程 ### 1. JWT Token验证 - 用户登录后获得JWT token - 所有需要认证的请求都需要在请求头中携带 `authorization` 字段 ### 2. 网关认证处理 网关通过 `AuthGlobalFilter` 处理用户认证: ```java // 1. 验证token Long userId = jwtTool.parseToken(token); // 2. 将用户ID添加到请求头 ServerHttpRequest newRequest = request.mutate() .header("user-info", userId.toString()) .build(); return chain.filter(exchange.mutate().request(newRequest).build()); ``` ### 3. 微服务用户信息获取 **重要:现在所有微服务都自动使用 `hm-common` 中的通用拦截器配置!** 由于所有微服务都依赖 `hm-common`,而 `hm-common` 中包含了 `MvcConfig` 配置类,所以: - **无需在每个微服务中单独配置拦截器** - **Spring Boot会自动扫描并应用 `hm-common` 中的配置** - **所有微服务都会自动处理 `user-info` 请求头** **重要配置:各微服务启动类需要添加组件扫描** 为了让Spring Boot能够扫描到 `hm-common` 中的配置类,需要在各个微服务的启动类中添加 `@ComponentScan` 注解: ```java @SpringBootApplication @ComponentScan(basePackages = {"com.hmall.服务名", "com.hmall.common"}) public class 服务Application { public static void main(String[] args) { SpringApplication.run(服务Application.class, args); } } ``` **已配置的微服务:** - ✅ `cart-service`: `@ComponentScan(basePackages = {"com.hmall.cart", "com.hmall.common"})` - ✅ `user-service`: `@ComponentScan(basePackages = {"com.hmall.user", "com.hmall.common"})` - ✅ `trade-service`: `@ComponentScan(basePackages = {"com.hmall.trade", "com.hmall.common"})` - ✅ `item-service`: `@ComponentScan(basePackages = {"com.hmall.item", "com.hmall.common"})` - ✅ `pay-service`: `@ComponentScan(basePackages = {"com.hmall.pay", "com.hmall.common"})` 通用拦截器配置位置:`hm-common/src/main/java/com/hmall/common/config/MvcConfig.java` ```java @Configuration public class MvcConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new HandlerInterceptor() { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { // 从请求头获取用户ID String userInfo = request.getHeader("user-info"); if (userInfo != null) { UserContext.setUser(Long.valueOf(userInfo)); } return true; } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { UserContext.removeUser(); } }); } } ``` ### 4. 业务代码中使用用户信息 ```java // 在任何微服务的业务代码中直接获取当前用户ID Long userId = UserContext.getUser(); ``` ## 架构优势 ### 统一配置管理 - **一处配置,处处生效**:所有微服务自动继承 `hm-common` 中的用户信息处理逻辑 - **维护简单**:只需要在 `hm-common` 中修改配置,所有微服务都会生效 - **避免重复代码**:不需要在每个微服务中重复编写相同的拦截器代码 ### 自动化处理 - **自动扫描**:Spring Boot自动扫描并应用 `hm-common` 中的 `@Configuration` 类 - **自动注入**:`UserContext` 自动处理用户信息的存储和清理 - **透明使用**:业务代码中可以直接使用 `UserContext.getUser()` 获取用户信息 ## 测试步骤和问题排查 ### 正确的测试方法 1. **获取JWT Token**: ```bash # 先登录获取token POST http://localhost:8080/users/login Content-Type: application/json { "username": "your_username", "password": "your_password" } ``` 2. **使用Token访问购物车接口**: ```bash # 通过网关访问购物车接口 GET http://localhost:8080/carts authorization: your_jwt_token_here ``` ### 常见错误和解决方案 #### 错误1:直接访问微服务 ```bash # ❌ 错误:直接访问微服务端口 GET http://localhost:8082/carts authorization: your_jwt_token_here ``` **问题**:绕过了网关,没有经过AuthGlobalFilter处理,不会有user-info请求头 #### 错误2:没有携带token ```bash # ❌ 错误:没有authorization请求头 GET http://localhost:8080/carts ``` **问题**:网关会返回401未授权 #### 错误3:token格式错误 ```bash # ❌ 错误:token格式不正确 GET http://localhost:8080/carts authorization: Bearer your_jwt_token_here ``` **问题**:可能token格式不对,检查是否需要Bearer前缀 ### 调试信息说明 当你正确测试时,应该看到以下调试信息: 1. **网关日志**: ``` 网关解析用户ID:123 ``` 2. **购物车服务拦截器日志**: ``` === 拦截器调试信息 === 请求路径: /carts user-info 请求头: 123 已将用户ID存入ThreadLocal: 123 ================== ``` 3. **购物车控制器日志**: ``` === 购物车服务调试信息 === 接收到的 user-info 请求头: 123 ThreadLocal中的用户ID: 123 ======================== ``` 4. **请求结束后**: ``` 已清理ThreadLocal中的用户信息 ``` ### 如果没有看到调试信息 1. **检查是否通过网关访问**:确保使用8080端口而不是8082端口 2. **检查token是否有效**:确保token没有过期且格式正确 3. **检查路径是否在白名单**:`/carts/**` 不在白名单中,需要token验证 4. **检查服务是否正常启动**:确保网关和购物车服务都正常运行 ## 重要说明 ### 测试接口时的注意事项 1. **必须通过网关访问**: - 正确:`http://localhost:8080/carts` (通过网关) - 错误:`http://localhost:8082/carts` (直接访问微服务) 2. **必须携带有效token**: - 在请求头中添加:`authorization: your-jwt-token` 3. **白名单路径**: 以下路径不需要token验证: - `/search/**` - `/users/login` - `/items/**` - `/hi` ### 常见问题排查 1. **Controller中的@RequestHeader没有打印值**: - 检查是否通过网关访问 - 检查是否携带了有效token - 检查微服务是否配置了拦截器 2. **UserContext.getUser()返回null**: - 检查微服务的MvcConfig配置 - 检查拦截器是否正确处理了user-info请求头 ## 启动顺序 1. 启动Nacos注册中心 2. 启动各个微服务 3. 启动网关服务 ## 配置文件说明 - JWT配置:`hm.jwt.*` - 认证配置:`hm.auth.*` - 数据库配置:`hm.db.*` ## MvcConfig 通用拦截器配置详解 ### 1. MvcConfig 类的位置和作用 `MvcConfig` 类位于 `hm-common/src/main/java/com/hmall/common/config/MvcConfig.java`,它是一个通用的MVC配置类,主要功能是: - **用户信息拦截器**:从HTTP请求头中获取网关传递的用户信息 - **ThreadLocal管理**:将用户ID存储到ThreadLocal中,供业务代码使用 - **自动清理**:请求完成后自动清理ThreadLocal,避免内存泄漏 ### 2. MvcConfig 的调用机制 #### 方式一:Spring Boot 自动配置(推荐) 通过 `hm-common/src/main/resources/META-INF/spring.factories` 文件实现自动配置: ```properties org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.hmall.common.config.MyBatisConfig,\ com.hmall.common.config.JsonConfig,\ com.hmall.common.config.MvcConfig ``` **优势**: - ✅ **自动生效**:只要微服务依赖了 `hm-common` 模块,`MvcConfig` 就会自动生效 - ✅ **无需手动配置**:不需要在每个微服务中添加任何配置代码 - ✅ **统一管理**:所有微服务使用相同的用户信息处理逻辑 #### 方式二:ComponentScan 扫描(备用方案) 在各个微服务的启动类中通过 `@ComponentScan` 扫描 `com.hmall.common` 包: **已配置的微服务**: - ✅ `cart-service`: `@ComponentScan(basePackages = {"com.hmall.cart", "com.hmall.common"})` - ✅ `user-service`: `@ComponentScan(basePackages = {"com.hmall.user", "com.hmall.common"})` - ✅ `trade-service`: `@ComponentScan(basePackages = {"com.hmall.trade", "com.hmall.common"})` - ✅ `item-service`: `@ComponentScan(basePackages = {"com.hmall.item", "com.hmall.common"})` - ✅ `pay-service`: `@ComponentScan(basePackages = {"com.hmall.pay", "com.hmall.common"})` ### 3. MvcConfig 的工作原理 ```java @Configuration public class MvcConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new HandlerInterceptor() { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { // 从请求头获取用户ID(网关传递) String userInfo = request.getHeader("user-info"); System.out.println("=== 拦截器调试信息 ==="); System.out.println("请求路径: " + request.getRequestURI()); System.out.println("user-info 请求头: " + userInfo); // 存入ThreadLocal if (userInfo != null) { UserContext.setUser(Long.valueOf(userInfo)); System.out.println("已将用户ID存入ThreadLocal: " + userInfo); } else { System.out.println("user-info 请求头为空"); } System.out.println("=================="); return true; } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { // 清理ThreadLocal,避免内存泄漏 UserContext.removeUser(); System.out.println("已清理ThreadLocal中的用户信息"); } }); } } ``` ### 4. 业务代码中使用用户信息 在任何微服务的业务代码中,都可以直接获取当前用户ID: ```java // 获取当前登录用户ID Long userId = UserContext.getUser(); // 示例:在购物车服务中使用 @Service public class CartServiceImpl implements CartService { public void addItemToCart(CartFormDTO cartFormDTO) { // 获取当前用户ID Long userId = UserContext.getUser(); // 业务逻辑... Cart cart = new Cart(); cart.setUserId(userId); cart.setItemId(cartFormDTO.getItemId()); // ... } } ``` ## 架构优势 ### 统一配置管理 - **一处配置,处处生效**:所有微服务自动继承 `hm-common` 中的用户信息处理逻辑 - **维护简单**:只需要在 `hm-common` 中修改配置,所有微服务都会生效 - **避免重复代码**:不需要在每个微服务中重复编写相同的拦截器代码 ### 自动化处理 - **Spring Boot 自动配置**:通过 `spring.factories` 实现自动装配 - **无侵入性**:业务代码无需关心用户信息的获取和存储细节 - **线程安全**:使用ThreadLocal确保多线程环境下的数据隔离 ### 调试友好 - **详细日志**:拦截器会打印详细的调试信息 - **请求追踪**:可以清楚看到每个请求的用户信息传递情况 - **问题排查**:便于定位用户信息传递过程中的问题 ## 总结 `MvcConfig` 类通过以下两种方式被调用: 1. **主要方式**:Spring Boot 自动配置机制(`spring.factories`) - 只要微服务依赖 `hm-common` 模块就会自动生效 - 无需任何手动配置 2. **备用方式**:`@ComponentScan` 扫描 - 在启动类中显式扫描 `com.hmall.common` 包 - 作为双重保障,确保配置生效 这种设计确保了用户信息处理逻辑的统一性和可维护性,是微服务架构中的最佳实践。