【微服务】Staffjoy 项目源码解析(六)—— Company 模块

一. 架构设计

在这里插入图片描述

这个 Company 模块的架构复杂度相较之前的情况又上了一筹。
上图估计很难看清楚,还是我去掉了 AppConfig 之类的不关键模块的基础上。

但还是有层次可分。

除了设定好的 Model 类外,类间可大致分为四层。
最底层,数据库接口层,提供七种数据对象与数据库的交互。
然后是 ServiceHelper 和 ShiftHelper 这俩辅助服务类。
特别是 ServiceHelper,可以说是其他 Service 的基础。
而 PermissionService 则是在每个 Controller 类内被调用的服务类,用于判断用户是否属于某数据对象。
再到顶层的 Controller 层,层中类方法与 CompanyClient 接口相关联。

二. 代码分析

因代码量较多,这次只调主要的 Service 层中的关键方法进行分析。

首先是 Service 层的根基 ServiceHelper 类

类中有 onboardWorkerAsync 方法,负责通知雇员的新工作等信息

    @Async(AppConfig.ASYNC_EXECUTOR_NAME)
    public void onboardWorkerAsync(OnboardWorkerRequest onboardWorkerRequest) {
        BaseResponse baseResponse = null;
        try {
            baseResponse = botClient.onboardWorker(onboardWorkerRequest);
        } catch (Exception ex) {
            String errMsg = "fail to call onboardWorker through botClient";
            handleErrorAndThrowException(logger, ex, errMsg);
        }
        if (!baseResponse.isSuccess()) {
            handleErrorAndThrowException(logger, baseResponse.getMessage());
        }
    }

基于 bot 模块中的数据类型进行传输

然后是 alertNewShiftAsync 方法,用于提醒新的班次信息

    @Async(AppConfig.ASYNC_EXECUTOR_NAME)
    public void alertNewShiftAsync(AlertNewShiftRequest alertNewShiftRequest) {
        BaseResponse baseResponse = null;
        try {
            baseResponse = botClient.alertNewShift(alertNewShiftRequest);
        } catch (Exception ex) {
            String errMsg = "failed to alert worker about new shift";
            handleErrorAndThrowException(logger, ex, errMsg);
        }
        if (!baseResponse.isSuccess()) {
            handleErrorAndThrowException(logger, baseResponse.getMessage());
        }
    }

还有 buildShiftNotificationAsync 方法,以列表显示通知所有 班次 的变跟

    @Async(AppConfig.ASYNC_EXECUTOR_NAME)
    public void buildShiftNotificationAsync(Map<String, List<ShiftDto>> notifs, boolean published) {
        for(Map.Entry<String, List<ShiftDto>> entry : notifs.entrySet()) {
            String userId = entry.getKey();
            List<ShiftDto> shiftDtos = entry.getValue();
            if (published) {
                // alert published
                AlertNewShiftsRequest alertNewShiftsRequest = AlertNewShiftsRequest.builder()
                        .userId(userId)
                        .newShifts(shiftDtos)
                        .build();
                BaseResponse baseResponse = null;
                try {
                    baseResponse = botClient.alertNewShifts(alertNewShiftsRequest);
                } catch (Exception ex) {
                    String errMsg = "failed to alert worker about new shifts";
                    handleErrorAndThrowException(logger, ex, errMsg);
                }
                if (!baseResponse.isSuccess()) {
                    handleErrorAndThrowException(logger, baseResponse.getMessage());
                }
            } else {
                // alert removed
                AlertRemovedShiftsRequest alertRemovedShiftsRequest = AlertRemovedShiftsRequest.builder()
                        .userId(userId)
                        .oldShifts(shiftDtos)
                        .build();
                BaseResponse baseResponse = null;
                try {
                    baseResponse = botClient.alertRemovedShifts(alertRemovedShiftsRequest);
                } catch (Exception ex) {
                    String errMsg = "failed to alert worker about removed shifts";
                    handleErrorAndThrowException(logger, ex, errMsg);
                }
                if (!baseResponse.isSuccess()) {
                    handleErrorAndThrowException(logger, baseResponse.getMessage());
                }
            }
        }
    }

主要是生成 AlertNewShiftsRequest 数据对象,传给 botClient 得到反馈

再到 AdminService 类,方法为增删查改,大同小异,选择增来进行分析。

    public DirectoryEntryDto createAdmin(String companyId, String userId) {
        Admin existing = adminRepo.findByCompanyIdAndUserId(companyId, userId);
        if (existing != null) {
            throw new ServiceException("user is already an admin");
        }

        DirectoryEntryDto directoryEntryDto = directoryService.getDirectoryEntry(companyId, userId);

        try {
            Admin admin = Admin.builder()
                    .companyId(companyId)
                    .userId(userId)
                    .build();
            adminRepo.save(admin);
        } catch (Exception ex) {
            String errMsg = "could not create the admin";
            serviceHelper.handleErrorAndThrowException(logger, ex, errMsg);
        }

        LogEntry auditLog = LogEntry.builder()
                .currentUserId(AuthContext.getUserId())
                .authorization(AuthContext.getAuthz())
                .targetType("admin")
                .targetId(userId)
                .companyId(companyId)
                .teamId("")
                .build();

        logger.info("added admin", auditLog);

        serviceHelper.trackEventAsync("admin_created");

        return directoryEntryDto;
    }

逻辑不复杂,通过传入的 companyId 和 userId 判断是否存在了 Admin
有就报错,没有再继续创建。
再根据上面的两个参数找到内部对象 DirectoryEntryDto
创建并存储 Admin 对象后,返回内部对象。

再挑 DirectoryService 的 updateDirectoryEntry 方法
代码量很大,逻辑也不复杂

    public DirectoryEntryDto updateDirectoryEntry(DirectoryEntryDto request) {
        DirectoryEntryDto orig = this.getDirectoryEntry(request.getCompanyId(), request.getUserId());

        GenericAccountResponse genericAccountResponse1 = null;
        try {
            genericAccountResponse1 = accountClient.getAccount(AuthConstant.AUTHORIZATION_COMPANY_SERVICE, orig.getUserId());
        } catch (Exception ex) {
            String errMsg = "getting account failed";
            serviceHelper.handleErrorAndThrowException(logger, ex, errMsg);
        }

        if (!genericAccountResponse1.isSuccess()) {
            serviceHelper.handleErrorAndThrowException(logger, genericAccountResponse1.getMessage());
        }

        AccountDto account = genericAccountResponse1.getAccount();

        boolean accountUpdateRequested =
                !request.getName().equals(orig.getName()) ||
                !request.getEmail().equals(orig.getEmail()) ||
                !request.getPhoneNumber().equals(orig.getPhoneNumber());
        if(account.isConfirmedAndActive() && accountUpdateRequested) {
            throw new ServiceException(ResultCode.PARAM_VALID_ERROR, "this user is active, so they cannot be modified");
        } else if (account.isSupport() && accountUpdateRequested) {
            throw new ServiceException(ResultCode.UN_AUTHORIZED, "you cannot change this account");
        }

        if (accountUpdateRequested) {
            account.setName(request.getName());
            account.setPhoneNumber(request.getPhoneNumber());
            account.setEmail(request.getEmail());
            GenericAccountResponse genericAccountResponse2 = null;
            try {
                genericAccountResponse2 = accountClient.updateAccount(AuthConstant.AUTHORIZATION_COMPANY_SERVICE, account);
            } catch (Exception ex) {
                String errMsg = "view updating account";
                serviceHelper.handleErrorAndThrowException(logger, ex, errMsg);
            }

            if (!genericAccountResponse2.isSuccess()) {
                serviceHelper.handleErrorAndThrowException(logger, genericAccountResponse2.getMessage());
            }

            copyAccountToDirectory(account, request);
        }

        try {
            directoryRepo.updateInternalIdByCompanyIdAndUserId(request.getInternalId(), request.getCompanyId(), request.getUserId());
        } catch (Exception ex) {
            String errMsg = "fail to update directory";
            serviceHelper.handleErrorAndThrowException(logger, ex, errMsg);
        }

        LogEntry auditLog = LogEntry.builder()
                .currentUserId(AuthContext.getUserId())
                .authorization(AuthContext.getAuthz())
                .targetType("directory")
                .targetId(account.getId())
                .companyId(request.getCompanyId())
                .teamId("")
                .originalContents(orig.toString())
                .updatedContents(request.toString())
                .build();

        logger.info("updated directory entry for account", auditLog);

        if (!request.isConfirmedAndActive() &&
                (!orig.getPhoneNumber().equals(request.getPhoneNumber()) || ("".equals(request.getPhoneNumber()) && !orig.getEmail().equals(request.getEmail())))) {
            OnboardWorkerRequest onboardWorkerRequest = OnboardWorkerRequest.builder()
                    .companyId(request.getCompanyId())
                    .userId(request.getUserId())
                    .build();
            serviceHelper.onboardWorkerAsync(onboardWorkerRequest);
        }

        serviceHelper.trackEventAsync("directoryentry_updated");

        return request;
    }

首先,通过封装好的 request 中的新 Directory 对象内的 userId 和 companyId 找到旧对象
再找到 account 对象,确保对象有不同后,修改 account 的属性进行更新。
再更新到内部对象 Directory,更新到底层数据库完成方法。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值