远程调用用户微服务及其他注意事项

与其他微服务一样,在购物车微服务中也需要完善 token 字段处理的逻辑,即在购物车微服务中调用用户微服务完成商城用户的鉴权及用户信息的获取。

第一步,增加配置,启用 OpenFeign 并使 FeignClient 类生效。

由于已经引入了 LoadBalancer 依赖和 user-api 依赖,因此这里可以直接通过 OpenFeign 来调用用户微服务中的接口用于商城用户的鉴权和信息获取。

打开 newbee-mall-cloud-shop-cart-web 工程,在项目的启动类 NewBeeMallCloudShopCartServiceApplication 中添加 @EnableFeignClients 注解,并配置相关的 FeignClient 类,代码如下:

@EnableFeignClients(basePackageClasses = {ltd.user.cloud.newbee.openfeign.NewBeeCloudUserServiceFeign.class})

这里使用 basePackageClasses 配置需要使用的 FeignClient 类,即 NewBeeCloudUserServiceFeign 类。接下来就可以直接使用 NewBeeCloudUserServiceFeign 类与用户微服务进行远程通信了。

第二步,修改 token 字段处理类中的逻辑代码。

打开 newbee-mall-cloud-shop-cart-web 工程,修改 TokenToMallUserMethodArgumentResolver 类中对 token 字段处理的逻辑代码,主要引入 NewBeeCloudUserServiceFeign 类,通过调用用户微服务来获取商城用户的数据。

修改后的代码如下:

@Component
public class TokenToMallUserMethodArgumentResolver implements HandlerMethodArgumentResolver {

    @Autowired
    private NewBeeCloudUserServiceFeign newBeeCloudUserService;

    public TokenToMallUserMethodArgumentResolver() {
    }

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        if (parameter.hasParameterAnnotation(TokenToMallUser.class)) {
            return true;
        }
        return false;
    }

    @Override
    public Object resolveArgument(MethodParameter parameter,
                                  ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest,
                                  WebDataBinderFactory binderFactory) throws Exception {
        if (parameter.hasParameterAnnotation(TokenToMallUser.class)) {
            String token = webRequest.getHeader("token");
            if (null != token && !"".equals(token) && token.length() == 32) {
                // 调用用户微服务,根据token字段获取商城用户的数据
                Result<MallUserDTO> result = newBeeCloudUserService.getMallUserByToken(token);
                if (result == null || result.getResultCode() != 200 ||
                        result.getData() == null) {
                    throw new NewBeeMallException.fail(ServiceResultEnum.TOKEN_EXPIRE_ERROR.getResult());
                }
                MallUserToken mallUserToken = new MallUserToken();
                mallUserToken.setToken(token);
                mallUserToken.setUserId(result.getData().getUserId());
                return mallUserToken;
            } else {
                NewBeeMallException.fail(ServiceResultEnum.NOT_LOGIN_ERROR.getResult());
            }
        }
        return null;
    }
}

如此便完成了在购物车微服务中通过远程通信获取当前登录用户信息的功能。

另外,购物车模块中的所有功能都只与商城用户相关,因此只需要处理商城用户即可。在全局异常处理类 ShopCartServiceExceptionHandler 中,由于购物车模块未涉及管理员用户账户,因此在区分自定义异常时有一些修改,要判断商城用户是否正常登录,未正常登录返回特定的响应代码 416(管理员用户未正常登录返回的响应代码为 419),代码如下:

@ExceptionHandler(Exception.class)
public Object handleException (Exception e, HttpServletRequest req) {
    Result result = new Result();
    result.setResultCode(500);
    //区分是否为自定义异常
    if (e instanceof NewBeeMallException) {
        result.setMessage(e.getMessage());
        //判断商城用户是否未正常登录,未正常登录返回特定的响应代码 416 (管理员用户未正常登录返回的响应代码为 419)
        if (e.getMessage().equals(ServiceResultEnum.NOT_LOGIN_ERROR.getResult()) || e.getMessage().equals(ServiceResultEnum.TOKEN_EXPIRE_ERROR.getResult())) {
            result.setResultCode(416);
        } else {
            e.printStackTrace();
            result.setMessage("未知异常,请查看控制台日志并检查配置文件。");
        }
    }
    return result;
}

此时的 newbee-mall-cloud-shop-cart-service 模块中没有业务代码,目录结构如图 7-1 所示。

image 2025 04 28 12 19 58 962
Figure 1. 图7-1 目录结构

这里并未涉及具体的业务代码,主要介绍购物车微服务的模块功能和表结构设计,以及在项目中完成购物车微服务的初始化构建,后续关于购物车微服务改造的实战章节都是基于当前项目来完成的。读者可以根据这些代码自己动手完成微服务编码,如获得这份代码后,以此为基础,自行完成购物车微服务模块所有代码的功能。如果自己实现耗费时间,也可以按照笔者给出的步骤完成服务化拆分。