站在巨人的肩膀上搬砖

导航

 

DDD领域驱动设计之代码重构

以用户功能为例

1. 重构前代码片段

  • UserController.java

/**
 * <p>
 * 前端控制器
 * </p>
 *
 * @author xujie
 * @since 2021-06-03
 */
@RestController
@RequestMapping("/user")
@Api(value = "用户", tags = "用户")
public class UserController {

    @Autowired
    private UserService userService;

    @ApiOperation(value = "统计用户有多少朋友", notes = "统计用户有多少朋友")
    @GetMapping("/friend/count")
    public KpResult<Integer> getUserHaveFriendNumber(@Valid @Size(max = 64, min = 16)
                                                             String userUniqueId) {
        KpResult<Integer> integerKpResult = new KpResult<>(userService.countUserHaveFriendNumber(userUniqueId));
        integerKpResult.setTraceId(MDC.get(TraceConstant.TRACE_KEY));
        return integerKpResult;
    }

    @ApiOperation(value = "获取当前用户个人信息", notes = "获取当前用户个人信息")
    @GetMapping("/current/query")
    public KpResult<UserDTO> getCurrentUser() {
        String currentUserUniqueId = CurrentUserUtil.getCurrentUserUniqueId();
        Optional.ofNullable(currentUserUniqueId).orElseThrow(() -> new CommonAssertException(ApplicationCodes.CUREENT_USER_NOT_EXIST));
        KpResult<UserDTO> userDTOKpResult = new KpResult<>(userService.selectCurrentUser(currentUserUniqueId));
        userDTOKpResult.setTraceId(MDC.get(TraceConstant.TRACE_KEY));
        return userDTOKpResult;
    }

    @ApiOperation(value = "登陆", notes = "登陆")
    @PostMapping(value = "/login")
    public KpResult<TokenDTO> login(@RequestBody @Valid LoginUserParam loginUserParam) {
        KpResult<TokenDTO> tokenDTOKpResult = new KpResult<>(userService.login(loginUserParam));
        tokenDTOKpResult.setTraceId(MDC.get(TraceConstant.TRACE_KEY));
        return tokenDTOKpResult;
    }

    @ApiOperation(value = "注册", notes = "注册")
    @PostMapping(value = "/register")
    public KpResult<Boolean> register(@RequestBody @Valid RegisterUserParam registerUserParam) {
        KpResult<Boolean> tokenDTOKpResult = new KpResult<>(userService.register(registerUserParam));
        tokenDTOKpResult.setTraceId(MDC.get(TraceConstant.TRACE_KEY));
        return tokenDTOKpResult;
    }


    @ApiOperation(value = "搜索用户", notes = "搜索用户")
    @PostMapping(value = "/search")
    public KpResult<PageDTO<List<UserDTO>>> search(@RequestBody @Valid SearchUserParam searchUserParam) {
        KpResult<PageDTO<List<UserDTO>>> result = new KpResult<PageDTO<List<UserDTO>>>();
        result.setData(userService.queryUser(searchUserParam));
        result.setTraceId(MDC.get(TraceConstant.TRACE_KEY));
        return result;
    }

    @ApiOperation(value = "更新用户", notes = "更新用户")
    @PostMapping(value = "/profile/update")
    public KpResult<Boolean> updateUser(@RequestBody @Valid UpdateUserParam updateUserParam) {
        KpResult<Boolean> result = new KpResult<Boolean>(userService.updateCurrentUser(updateUserParam));
        result.setTraceId(MDC.get(TraceConstant.TRACE_KEY));
        return result;
    }

    @ApiOperation(value = "当前用户朋友", notes = "当前用户朋友")
    @PostMapping(value = "/my/friend")
    public KpResult<PageDTO<List<UserDTO>>> query(@RequestBody @Valid Pageable pageable) {
        String currentUserUniqueId = CurrentUserUtil.getCurrentUserUniqueId();
        Optional.ofNullable(currentUserUniqueId).orElseThrow(() -> new CommonAssertException(ApplicationCodes.CUREENT_USER_NOT_EXIST));
        KpResult<PageDTO<List<UserDTO>>> result = new KpResult<PageDTO<List<UserDTO>>>(userService.queryMyFriend(pageable, currentUserUniqueId));
        result.setTraceId(MDC.get(TraceConstant.TRACE_KEY));
        return result;
    }

    @ApiOperation(value = "朋友邀请码", notes = "朋友邀请码")
    @PostMapping(value = "/my/friend/code/get")
    public KpResult<String> getInvite() {
        String currentUserUniqueId = CurrentUserUtil.getCurrentUserUniqueId();
        Optional.ofNullable(currentUserUniqueId).orElseThrow(() -> new CommonAssertException(ApplicationCodes.CUREENT_USER_NOT_EXIST));
        KpResult<String> result = new KpResult<String>(userService.createInvite(currentUserUniqueId));
        result.setTraceId(MDC.get(TraceConstant.TRACE_KEY));
        return result;
    }

    @ApiOperation(value = "登录验证码", notes = "登录验证码")
    @GetMapping(value = "/login/verification/code/get")
    public KpResult<String> getVerificationCodeByPhone(@Valid
                                                @Size(max = 11, min = 11)
                                                @NotEmpty
                                                        String phone) {
        Optional.ofNullable(phone).orElseThrow(() -> new CommonAssertException(ApplicationCodes.CUREENT_USER_NOT_EXIST));
        KpResult<String> result = new KpResult<String>(userService.getVerificationCodeByPhone(phone));
        result.setTraceId(MDC.get(TraceConstant.TRACE_KEY));
        return result;
    }

}
  • UserServiceImpl.java
/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author xujie
 * @since 2021-06-03
 */
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, TUser> implements UserService {

    @Autowired
    private UserHelper        userHelper;
    @Autowired
    private FriendService     friendService;
    @Autowired
    private IIdGenerator      iIdGenerator;
    @Autowired
    private BsProvinceHelper  bsProvinceHelper;
    @Autowired
    private BsAreaHelper      bsAreaHelper;
    @Autowired
    private AreaUtil          areaUtil;
    @Autowired
    private UserConfigService userConfigService;
    @Autowired
    private RedisUtil         redisUtil;
    @Autowired
    private AliOssUtil        ossUtil;
    @Autowired
    private AliSmsUtil        smsUtil;

    @RedisCache(key = "user.by.user.id", fieldKey = "#userUniqueId")
    @Override
    public Integer countUserHaveFriendNumber(String userUniqueId) {
        Optional.ofNullable(userUniqueId).orElseThrow(() -> new CommonAssertException(CommonConstant.REQUEST_PARAM_ERROR));
        TUser user = userHelper.selectByUserUniqueId(userUniqueId);
        Optional.ofNullable(user).orElseThrow(() -> new CommonAssertException(ApplicationCodes.USER_NOT_EXIST));

        return friendService.selectCountUserHaveFriendNumber(userUniqueId);
    }

    @RedisCache(key = "user.by.current.user.id", fieldKey = "#currentUserUniqueId")
    @Override
    public UserDTO selectCurrentUser(String currentUserUniqueId) {
        UserDTO userDTO = new UserDTO();
        TUser   user    = userHelper.selectByUserUniqueId(currentUserUniqueId);
        Optional.ofNullable(user).orElseThrow(() -> new CommonAssertException(ApplicationCodes.USER_NOT_EXIST));

        //个人隐私设置
        UserConfig    dbUserConfig = userConfigService.selectByUserUniqueId(currentUserUniqueId);
        UserConfigDTO userConfig   = new UserConfigDTO();
        userConfig.setUserUniqueId(dbUserConfig.getUserUniqueId());
        userConfig.setUserConfigUniqueId(dbUserConfig.getUserConfigUniqueId());
        userConfig.setVisbleBase(dbUserConfig.getIsVisibleAge());
        userConfig.setVisbleName(dbUserConfig.getIsVisibleName());
        userConfig.setVisblePhone(dbUserConfig.getIsVisiblePhone());
        userConfig.setVisbleQq(dbUserConfig.getIsVisibleQq());
        userConfig.setVisbleWeixin(dbUserConfig.getIsVisibleWeixin());
        userDTO.setUserConfigDTO(userConfig);

        BeanUtils.copyProperties(user, userDTO, "password");
        userDTO.setAvatar(ossUtil.getUrl(ossUtil.getAvatarBucketName(), currentUserUniqueId, CommonConstant.AVATAR_TTL));
        userDTO.setBirthday(user.getBirthday());
        if (Objects.nonNull(user.getApprovalTime())) {
            userDTO.setApprovalTime(String.format("%d年%d月%d日", user.getApprovalTime().getYear(), user.getApprovalTime().getMonth().getValue(), user.getApprovalTime().getDayOfMonth()));
        }
        // 统计
        StatisticsDTO statisticsDTO = new StatisticsDTO();
        //统计多少朋友
        Integer total = friendService.selectCountUserHaveFriendNumber(currentUserUniqueId);
        statisticsDTO.setCountFriend(total);
        //获取朋友分布
        List<Friend> friends = friendService.selectByUserUniqueId(currentUserUniqueId);
        statisticsDTO.setFriendInArea(getFriendsInArea(friends));
        //月结识率
        Integer countInMonth = friendService.selectCountFriendInDayByUserUniqueId(currentUserUniqueId, 30);
        if (total != 0) {
            DecimalFormat decimalFormat = new DecimalFormat("0.00");
            decimalFormat.format((float) countInMonth / total);
            BigDecimal countInMonthBigDecimal = new BigDecimal(countInMonth);
            BigDecimal totalBigDecimal        = new BigDecimal(total);
            BigDecimal divide                 = countInMonthBigDecimal.divide(totalBigDecimal, BigDecimal.ROUND_HALF_UP);
            BigDecimal hundred                = new BigDecimal(100);
            statisticsDTO.setMakeFriendsInMonthRate(String.format("%s%%", divide.multiply(hundred)));
        }
        userDTO.setStatisticsDTO(statisticsDTO);
        return userDTO;
    }

    private List<String> getFriendsInArea(List<Friend> friends) {
        if (!CollectionUtils.isEmpty(friends)) {
            Set<String> friendUserUniqueIds = friends.stream().
                    map(Friend::getFriendUniqueId).collect(Collectors.toSet());
            List<TUser> userFriends = userHelper.selectByUserUniqueIds(friendUserUniqueIds);
            if (CollectionUtils.isEmpty(userFriends)) {
                throw new CommonAssertException(ApplicationCodes.USER_FRIEND_NOT_EXIST);
            }

            List<String> userFriendCurrentHomeList = userFriends.stream()
                    .map(TUser::getCurrentHome).collect(Collectors.toList());
            // 去重
            Set<String> provinceAndAreaCodes = Sets.newHashSet();
            if (!CollectionUtils.isEmpty(userFriendCurrentHomeList)) {
                userFriendCurrentHomeList.stream().forEach(userFriendCurrentHome -> {
                    if (StringUtils.isNotEmpty(userFriendCurrentHome)) {
                        String[] area = userFriendCurrentHome.split(AREA_SPLIT);
                        // format : province_code,city_code,area_code,street_code
                        provinceAndAreaCodes.add(area[0] + AREA_SPLIT + area[2]);
                    }
                });

                Set<String> provinceCodes = Sets.newHashSet();
                Set<String> areaCodes     = Sets.newHashSet();
                if (!CollectionUtils.isEmpty(provinceAndAreaCodes)) {
                    provinceAndAreaCodes.stream().forEach(provinceAndAreaCode -> {
                        String[] provinceAndAreaCodeArr = provinceAndAreaCode.split(AREA_SPLIT);
                        // format : province_code,area_code
                        provinceCodes.add(provinceAndAreaCodeArr[0]);
                        areaCodes.add(provinceAndAreaCodeArr[1]);
                    });
                }

                List<BsProvince> bsProvinces = Lists.newArrayList();
                if (!CollectionUtils.isEmpty(provinceCodes)) {
                    bsProvinces.addAll(bsProvinceHelper.selectByProvinceCodes(provinceCodes));
                }
                List<BsArea> bsAreas = Lists.newArrayList();
                if (!CollectionUtils.isEmpty(areaCodes)) {
                    bsAreas.addAll(bsAreaHelper.selectByAreaCodes(areaCodes));
                }

                if (!CollectionUtils.isEmpty(provinceCodes) && !CollectionUtils.isEmpty(areaCodes) && provinceCodes.size() != areaCodes.size()) {
                    throw new CommonAssertException(ApplicationCodes.USER_CURRENT_HOME);
                }

                List<String> formatAreaList = Lists.newArrayList();
                //拼装 format : {province_name,area_name}
                provinceAndAreaCodes.stream().forEach(provinceAndAreaCode -> {
                    String formatArea = "";
                    for (int i = 0; i < bsProvinces.size(); i++) {
                        formatArea = bsProvinces.get(i).getShortName() + "," + bsAreas.get(i).getShortName();
                        formatAreaList.add(String.format("{%s}", formatArea));
                    }

                    formatAreaList.add(String.format("{%s}", formatArea));
                });

                return formatAreaList;
            }

        }
        return Collections.EMPTY_LIST;
    }

    @Override
    public TokenDTO login(LoginUserParam loginUserParam) {
        TUser userByPhone = userHelper.findUserByPhone(loginUserParam.getUserName());
        Optional.ofNullable(userByPhone).orElseThrow(() -> new CommonAssertException(ApplicationCodes.USER_NOT_EXIST));

        //审核通过才放行
        if (!Objects.equals(userByPhone.getApprovalStatus(), UserApprovalStatusEnum.PASSED.getCode())) {
            return new TokenDTO();
        }
//        TODO 待上线 去掉注解即可 验证码通过放行
        String defaultKey = CommonConstant.GET_LOGIN_VERIFICATION_CODE_KEY + StringUtils.trim(loginUserParam.getUserName());
        Object code       = redisUtil.get(defaultKey);
        if (Objects.isNull(code)) {
            throw new CommonAssertException(ApplicationCodes.VERIFICATION_CODE_NOT_EXIST);
        }

        if (!Objects.equals(code.toString(), StringUtils.trim(loginUserParam.getValidateCode()))) {
            throw new CommonAssertException(ApplicationCodes.VERIFICATION_CODE_IS_ERROR);
        }

        if (Objects.equals(userByPhone.getPassword(), Md5Util.getMD5(StringUtils.trim(loginUserParam.getPassword())))) {
            String jwt = CurrentUserUtil.createJWT(userByPhone.getUserUniqueId(),
                    userByPhone.getUserUniqueId(),
                    CommonConstant.JWT_TTL);
            TokenDTO tokenDTO = new TokenDTO();
            tokenDTO.setToken(jwt);
            tokenDTO.setLevel(userByPhone.getApprovalLevel());
            tokenDTO.setUserUniqueId(userByPhone.getUserUniqueId());
            tokenDTO.setNickName(userByPhone.getNickName());
            redisUtil.delete(defaultKey);
            return tokenDTO;
        } else {
            throw new CommonAssertException(ApplicationCodes.USER_PASSWORD_ERROR);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean register(RegisterUserParam userParam) {
        Optional.ofNullable(userParam).orElseThrow(() -> new CommonAssertException(CommonConstant.REQUEST_PARAM_ERROR));
        TUser register = new TUser();
        register.setNickName(SampleRandomUtil.getRandomString(5));
        register.setPassword(Md5Util.getMD5(StringUtils.trim(userParam.getPassword())));
        register.setPhone(StringUtils.trim(userParam.getUserName()));
        register.setUserUniqueId(iIdGenerator.getHexId());
        register.setApprovalTime(LocalDateTime.now());
        boolean validateInvite = validateInvite(userParam.getInviteCode());
        if (!validateInvite) {
            throw new CommonAssertException(ApplicationCodes.USER_INVITE_ERROR);
        }
        // 存的是邀请人的 userUniqueId
        String inviteCodeValue = getInviteCodeValueToUserUniqueId(userParam.getInviteCode());
        register.setInviteBy(inviteCodeValue);
        register.setApprovalStatus(UserApprovalStatusEnum.PASSED.getCode());
        UserConfig userConfig = getUserRegisterDefaultConfig(register);
        if (userHelper.insert(register) && userConfigService.insert(userConfig)) {

            Friend friend = new Friend();
            friend.setApprovalStatus(FriendApprovalStatusEnum.PASSED.getCode());
            friend.setUserUniqueId(inviteCodeValue);
            friend.setFriendUniqueId(register.getUserUniqueId());
            friendService.insert(friend);

            Friend self = new Friend();
            self.setApprovalStatus(FriendApprovalStatusEnum.PASSED.getCode());
            self.setUserUniqueId(register.getUserUniqueId());
            self.setFriendUniqueId(inviteCodeValue);
            friendService.insert(self);

            // 清除redis key
            redisUtil.delete(CommonConstant.INVITE_CODE + userParam.getInviteCode());
            redisUtil.delete(CommonConstant.USER_INVITE_CODE_KEY + inviteCodeValue);
            return true;
        }
        return false;
    }

    private UserConfig getUserRegisterDefaultConfig(TUser user) {
        UserConfig userConfig = new UserConfig();
        userConfig.setIsIncludedSearchAge(YesNoEnum.NO.getCode());
        userConfig.setIsIncludedSearchBirthday(YesNoEnum.NO.getCode());
        userConfig.setIsIncludedSearchCurrentHome(YesNoEnum.NO.getCode());
        userConfig.setIsVisibleCurrentDynamic(YesNoEnum.YES.getCode());
        userConfig.setIsVisibleCurrentHome(YesNoEnum.NO.getCode());
        userConfig.setIsIncludedSearchDouyin(YesNoEnum.NO.getCode());
        userConfig.setIsIncludedSearchFeelingStatus(YesNoEnum.NO.getCode());
        userConfig.setIsIncludedSearchKuaishou(YesNoEnum.NO.getCode());
        userConfig.setIsIncludedSearchMe(YesNoEnum.NO.getCode());
        userConfig.setIsIncludedSearchNickName(YesNoEnum.YES.getCode());
        userConfig.setIsVisibleAge(YesNoEnum.NO.getCode());
        userConfig.setIsVisibleWeixin(YesNoEnum.NO.getCode());
        userConfig.setIsVisiblePhone(YesNoEnum.NO.getCode());
        userConfig.setIsVisibleName(YesNoEnum.NO.getCode());
        userConfig.setIsIncludedSearchOriginalFamilyHome(YesNoEnum.NO.getCode());
        userConfig.setIsIncludedSearchPhone(YesNoEnum.NO.getCode());
        userConfig.setIsIncludedSearchQq(YesNoEnum.NO.getCode());
        userConfig.setIsIncludedSearchSex(YesNoEnum.NO.getCode());
        userConfig.setIsIncludedSearchWeixin(YesNoEnum.NO.getCode());
        userConfig.setIsVisibleCurrentDynamic(YesNoEnum.NO.getCode());
        userConfig.setIsVisibleGoodCounter(YesNoEnum.NO.getCode());
        userConfig.setUserUniqueId(user.getUserUniqueId());
        userConfig.setUserConfigUniqueId(iIdGenerator.getIdStr());
        userConfig.setIsVisibleWork(YesNoEnum.NO.getCode());
        userConfig.setIsIncludedSearchWork(YesNoEnum.NO.getCode());
        userConfig.setIsVisibleIdCard(YesNoEnum.NO.getCode());
        userConfig.setIsIncludedSearchIdCard(YesNoEnum.NO.getCode());
        return userConfig;
    }


    @Override
    public PageDTO<List<UserDTO>> queryUser(SearchUserParam searchUserParam) {
        String currentUserUniqueId = CurrentUserUtil.getCurrentUserUniqueId();
        Optional.ofNullable(currentUserUniqueId).orElseThrow(() -> new CommonAssertException(ApplicationCodes.CUREENT_USER_NOT_EXIST));
        // 如果要查朋友的朋友 商品名称 会多出来几个 left join 影响性能
        // searchUserParam.getGoodName()
        TUser current = userHelper.selectByUserUniqueId(currentUserUniqueId);
        Optional.ofNullable(current).orElseThrow(() -> new CommonAssertException(ApplicationCodes.CUREENT_USER_NOT_EXIST));

        Page<TUser> page = userHelper.selectByCondition(searchUserParam.getPageNo(), searchUserParam.getPageSize(),
                searchUserParam.getSearchWord(), currentUserUniqueId);

        List<UserDTO> userDTOList = Lists.newArrayList();
        List<TUser>   records     = page.getRecords();
        if (!CollectionUtils.isEmpty(records)) {
            Set<String> userUniqueIds = records.stream().map(TUser::getUserUniqueId).collect(Collectors.toSet());
            // NOTE ids -> select single redis, 避免搜索组合过多导致redis宕机
            List<UserConfigDTO> userConfigDTOS = Lists.newArrayList();
            userUniqueIds.stream().forEach(userUniqueId -> {
                UserConfig    userConfig       = userConfigService.selectByUserUniqueId(userUniqueId);
                UserConfigDTO userConfigDTO    = new UserConfigDTO();
                UserConfigDTO newUserConfigDTO = UserConvert.daoToConfigDTO(userConfigDTO, userConfig);
                userConfigDTOS.add(newUserConfigDTO);
            });
            Optional.ofNullable(userConfigDTOS).orElseThrow(() -> new CommonAssertException(ApplicationCodes.USER_CONFIG_NOT_EXIST));
            //  处理用户设置的安全隐私问题
            if (CollectionUtils.isEmpty(userConfigDTOS)) {
                throw new CommonAssertException(ApplicationCodes.USER_SAFE_CONFIG_NOT_EXIST);
            }
            Map<String, UserConfigDTO> userConfigMap = userConfigDTOS.stream().collect(Collectors.toMap(it -> it.getUserUniqueId(), it -> it));
            // 处理朋友关系
            // NOTE ids -> select single redis, 避免搜索组合过多导致redis宕机
            List<Friend> friendList = Lists.newArrayList();
            userUniqueIds.stream().forEach(userUniqueId -> {
                friendList.addAll(friendService.selectByUserUniqueId(userUniqueId));
            });
            Map<String, TUser>        searchMappingToMapper = Maps.newHashMap();
            Map<String, List<Friend>> searchFriendMapper    = Maps.newHashMap();
            if (!CollectionUtils.isEmpty(friendList)) {
                Map<String, List<Friend>> searchFriendMap = friendList.stream()
                        .collect(Collectors.groupingBy(Friend::getUserUniqueId));
                searchFriendMapper.putAll(searchFriendMap);
                List<TUser> users = userHelper.selectByUserUniqueIds(friendList.stream().map(Friend::getFriendUniqueId).collect(Collectors.toSet()));
                Optional.ofNullable(users).orElseThrow(() -> new CommonAssertException(ApplicationCodes.USER_NOT_EXIST));
                searchMappingToMapper.putAll(users.stream().collect(Collectors.toMap(it -> it.getUserUniqueId(), it -> it)));
            }
            // 我的朋友
            List<Friend> myFriends          = friendService.selectByUserUniqueId(currentUserUniqueId);
            List<String> myFriendsUniqueIds = Lists.newArrayList();
            if (!CollectionUtils.isEmpty(myFriends)) {
                myFriendsUniqueIds.addAll(myFriends.stream().map(Friend::getFriendUniqueId).collect(Collectors.toSet()));
            }
            records.stream().forEach(user -> {
                UserConfigDTO userConfig       = userConfigMap.get(user.getUserUniqueId());
                List<Friend>  searchFriendList = searchFriendMapper.get(user.getUserUniqueId());

                UserDTO userDTO = new UserDTO();
                userDTO.setUserUniqueId(user.getUserUniqueId());
                userDTO.setAvatar(ossUtil.getUrl(ossUtil.getAvatarBucketName(), user.getUserUniqueId(), CommonConstant.AVATAR_TTL));
                userDTO.setName(getDisplayText(Objects.equals(userConfig.getVisbleName(), YesNoEnum.YES.getCode()), user.getName()));
                userDTO.setAge(Objects.equals(userConfig.getVisbleBase(), YesNoEnum.YES.getCode()) ? user.getAge() : null);
                userDTO.setSex(Objects.equals(userConfig.getVisbleBase(), YesNoEnum.YES.getCode()) ? user.getSex() : null);
                userDTO.setFeelingStatus(Objects.equals(userConfig.getVisbleBase(), YesNoEnum.YES.getCode()) ? user.getFeelingStatus() : null);
                String displayBirthdayText = getDisplayText(Objects.equals(userConfig.getVisbleBase(), YesNoEnum.YES.getCode()),
                        user.getBirthday());
                userDTO.setBirthday(displayBirthdayText);

                userDTO.setCurrentDynamic(getDisplayText(Objects.equals(userConfig.getVisbleBase(), YesNoEnum.YES.getCode()), user.getCurrentDynamic()));
                String currentHome = areaUtil.getFormartDisplayArea(user.getCurrentHome());
                if (StringUtils.isNotEmpty(currentHome) && currentHome.split(AREA_SPLIT).length == 4) {
                    String[] split = currentHome.split(AREA_SPLIT);
                    currentHome = split[0] + "," + split[2];
                }
                String forMartFamilyHome = "";
                if (StringUtils.isNotEmpty(user.getOriginalFamilyHome())) {
                    forMartFamilyHome = areaUtil.getFormartDisplayArea(user.getOriginalFamilyHome());
                    if (StringUtils.isNotEmpty(forMartFamilyHome) && forMartFamilyHome.split(AREA_SPLIT).length == 4) {
                        String[] split = forMartFamilyHome.split(AREA_SPLIT);
                        forMartFamilyHome = split[0] + "," + split[2];
                    }
                }
                userDTO.setNickName(getDisplayText(Objects.equals(userConfig.getVisbleBase(), YesNoEnum.YES.getCode()), user.getNickName()));
                userDTO.setWeixin(getDisplayText(Objects.equals(userConfig.getVisbleWeixin(), YesNoEnum.YES.getCode()), user.getWeixin()));
                userDTO.setQq(getDisplayText(Objects.equals(userConfig.getVisbleQq(), YesNoEnum.YES.getCode()), user.getQq()));
                userDTO.setPhone(getDisplayText(Objects.equals(userConfig.getVisblePhone(), YesNoEnum.YES.getCode()), user.getPhone()));
                userDTO.setApprovalLevel(user.getApprovalLevel());
                // 搜索的人中有我朋友的朋友
                if (!CollectionUtils.isEmpty(searchFriendList) && !CollectionUtils.isEmpty(myFriends)) {
                    Set<Friend> includeFriends = searchFriendList.stream()
                            .filter(searchFriend -> myFriendsUniqueIds.contains(searchFriend.getFriendUniqueId()))
                            .collect(Collectors.toSet());

                    List<TUser> includeFriendMappingToUserList = Lists.newArrayList();
                    includeFriends.stream().forEach(includeFriend -> {
                        includeFriendMappingToUserList.add(searchMappingToMapper.get(includeFriend.getUserUniqueId()));
                    });

                    userDTO.setIncludeMyFriendStr(includeFriendMappingToUserList.stream().map(TUser::getNickName).collect(Collectors.joining(",")));
                }
                userDTO.setProfile(String.format("%s\n", userDTO.toString()));
                userDTOList.add(userDTO);
            });
        }

        PageDTO<List<UserDTO>> pageDTO = new PageDTO<>();
        pageDTO.setPageNo((int) page.getCurrent());
        pageDTO.setPageSize((int) page.getSize());
        pageDTO.setTotal((int) page.getTotal());
        pageDTO.setData(userDTOList);
        pageDTO.isHasMore(pageDTO.getTotal(), pageDTO.getPageNo(), pageDTO.getPageSize());
        return pageDTO;
    }

    @RedisEvictByKeysOnPrefix(prefix = "user", fieldKey = "#updateUserParam.userUniqueId")
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateCurrentUser(UpdateUserParam updateUserParam) {
        if (Objects.isNull(updateUserParam)) {
            throw new CommonAssertException(ApplicationCodes.UPDATE_CURRENT_USER_PARAM_NOT_EXIST);
        }
        String userUniqueId = updateUserParam.getUserUniqueId();
        if (!Objects.equals(CurrentUserUtil.getCurrentUserUniqueId(), userUniqueId)) {
            throw new CommonAssertException(ApplicationCodes.UPDATE_CURRENT_USER_NO_AUTH);
        }
        TUser dbUser = userHelper.selectByUserUniqueId(userUniqueId);
        if (Objects.isNull(dbUser)) {
            throw new CommonAssertException(ApplicationCodes.USER_NOT_EXIST);
        }
        boolean updateUser = userHelper.updateUser(UserConvert.paramToDAO(dbUser, updateUserParam));
        if (updateUser) {
            UserConfig dbUserConfig = userConfigService.selectByUserUniqueId(userUniqueId);
            if (Objects.isNull(dbUserConfig)) {
                throw new CommonAssertException(ApplicationCodes.USER_CONFIG_NOT_EXIST);
            }
            UserConfig update = UserConvert.paramToConfigDAO(dbUserConfig, updateUserParam);
            return userConfigService.updateUserConfig(update);
        }

        return false;
    }

    @Override
    public PageDTO<List<UserDTO>> queryMyFriend(Pageable pageable, String currentUserUniqueId) {
        Optional.ofNullable(currentUserUniqueId).orElseThrow(() -> new CommonAssertException(ApplicationCodes.USER_NOT_EXIST));
        Page<Friend> friendPage = friendService.selectByUserUniqueIdPageable(pageable, currentUserUniqueId);
        if (!CollectionUtils.isEmpty(friendPage.getRecords())) {
            Set<String> myFriendsUniqueIds = friendPage.getRecords().stream().map(Friend::getFriendUniqueId).collect(Collectors.toSet());
            List<TUser> myFriendUsers      = userHelper.selectByUserUniqueIds(myFriendsUniqueIds);
            Optional.ofNullable(myFriendUsers).orElseThrow(() -> new CommonAssertException(ApplicationCodes.USER_NOT_EXIST));
            List<UserConfigDTO> userConfigDTOS = userConfigService.selectByUserUniqueIds(myFriendsUniqueIds);
            if (CollectionUtils.isEmpty(userConfigDTOS)) {
                throw new CommonAssertException(ApplicationCodes.USER_CONFIG_NOT_EXIST);
            }
            Map<String, UserConfigDTO> userConfigMap = userConfigDTOS.stream().collect(Collectors.toMap(it -> it.getUserUniqueId(), it -> it));
            List<UserDTO>              userDTOList   = Lists.newArrayList();

            myFriendUsers.stream().forEach(user -> {
                UserConfigDTO userConfig = userConfigMap.get(user.getUserUniqueId());
                UserDTO       userDTO    = new UserDTO();
                userDTO.setUserUniqueId(user.getUserUniqueId());
                userDTO.setAvatar(ossUtil.getUrl(ossUtil.getAvatarBucketName(), user.getUserUniqueId(), CommonConstant.AVATAR_TTL));
                userDTO.setName(getDisplayText(Objects.equals(userConfig.getVisbleName(), YesNoEnum.YES.getCode()), user.getName()));
                userDTO.setAge(Objects.equals(userConfig.getVisbleBase(), YesNoEnum.YES.getCode()) ? user.getAge() : null);
                userDTO.setSex(Objects.equals(userConfig.getVisbleBase(), YesNoEnum.YES.getCode()) ? user.getSex() : null);
                userDTO.setFeelingStatus(Objects.equals(userConfig.getVisbleBase(), YesNoEnum.YES.getCode()) ? user.getFeelingStatus() : null);
                String displayBirthdayText = getDisplayText(Objects.equals(userConfig.getVisbleBase(), YesNoEnum.YES.getCode()),
                        user.getBirthday());
                userDTO.setBirthday(displayBirthdayText);

                userDTO.setCurrentDynamic(getDisplayText(Objects.equals(userConfig.getVisbleBase(), YesNoEnum.YES.getCode()), user.getCurrentDynamic()));
                String currentHome = areaUtil.getFormartDisplayArea(user.getCurrentHome());
                if (StringUtils.isNotEmpty(currentHome) && currentHome.split(AREA_SPLIT).length == 4) {
                    String[] split = currentHome.split(AREA_SPLIT);
                    currentHome = split[0] + "," + split[2];
                }
                String forMartFamilyHome = "";
                if (StringUtils.isNotEmpty(user.getOriginalFamilyHome())) {
                    forMartFamilyHome = areaUtil.getFormartDisplayArea(user.getOriginalFamilyHome());
                    if (StringUtils.isNotEmpty(forMartFamilyHome) && forMartFamilyHome.split(AREA_SPLIT).length == 4) {
                        String[] split = forMartFamilyHome.split(AREA_SPLIT);
                        forMartFamilyHome = split[0] + "," + split[2];
                    }
                }
                userDTO.setNickName(getDisplayText(Objects.equals(userConfig.getVisbleBase(), YesNoEnum.YES.getCode()), user.getNickName()));
                userDTO.setWeixin(getDisplayText(Objects.equals(userConfig.getVisbleWeixin(), YesNoEnum.YES.getCode()), user.getWeixin()));
                userDTO.setQq(getDisplayText(Objects.equals(userConfig.getVisbleQq(), YesNoEnum.YES.getCode()), user.getQq()));
                userDTO.setPhone(getDisplayText(Objects.equals(userConfig.getVisblePhone(), YesNoEnum.YES.getCode()), user.getPhone()));
                userDTO.setApprovalLevel(user.getApprovalLevel());
                userDTO.setWork(user.getWork());
                userDTO.setProfile(String.format("%s\n", userDTO.toString()));
                userDTOList.add(userDTO);
            });
            PageDTO<List<UserDTO>> pageDTO = new PageDTO<>();
            pageDTO.setData(userDTOList);
            pageDTO.setTotal((int) friendPage.getTotal());
            pageDTO.setPageSize((int) friendPage.getSize());
            pageDTO.setPageNo((int) friendPage.getCurrent());
            pageDTO.isHasMore(pageDTO.getTotal(), pageDTO.getPageNo(), pageDTO.getPageSize());
            return pageDTO;
        }
        return new PageDTO<>();
    }

    @Override
    public String createInvite(String currentUserUniqueId) {
        TUser tUser = userHelper.selectByUserUniqueId(currentUserUniqueId);
        Optional.ofNullable(tUser).orElseThrow(() -> new CommonAssertException(ApplicationCodes.USER_NOT_EXIST));
        String substring     = tUser.getPhone().substring(7, 11);
        String inviteCodeKey = CommonConstant.USER_INVITE_CODE_KEY + currentUserUniqueId;
        Object code          = redisUtil.get(inviteCodeKey);
        if (Objects.isNull(code)) {
            String randomString      = SampleRandomUtil.getRandomString(currentUserUniqueId, 4);
            String validateCodeValue = substring + randomString;
            redisUtil.set(inviteCodeKey, validateCodeValue, 60 * 5);
            redisUtil.set(CommonConstant.INVITE_CODE + validateCodeValue, currentUserUniqueId, 60 * 5);
            return validateCodeValue;
        }
        return code.toString();
    }

    @Override
    public boolean validateInvite(String code) {
        if (StringUtils.isEmpty(code)) {
            return false;
        }
        if (code.length() != 8) {
            return false;
        }
        Object inviteUserUniqueId = redisUtil.get(CommonConstant.INVITE_CODE + code);
        if (Objects.isNull(inviteUserUniqueId)) {
            return false;
        }
        //code:前四位是邀请用户手机号后四位
        String       validateCode           = code.substring(4, 8);
        char[]       chars                  = validateCode.toCharArray();
        CharSequence inviteCodeCharSequence = (CharSequence) inviteUserUniqueId;
        for (int i = 0; i < chars.length; i++) {
            if (!StringUtils.contains(inviteCodeCharSequence, chars[i])) {
                return false;
            }
        }
        return true;
    }

    @Override
    public String getInviteCodeValueToUserUniqueId(String code) {
        if (StringUtils.isEmpty(code)) {
            return "";
        }
        Object inviteCode = redisUtil.get(CommonConstant.INVITE_CODE + code);
        if (Objects.isNull(inviteCode)) {
            return "";
        }
        return inviteCode.toString();
    }

    @Override
    public String getVerificationCodeByPhone(String phone) {
        Optional.ofNullable(phone).orElseThrow(() -> new CommonAssertException(ApplicationCodes.USER_PHONE_NOT_EMPTY));
        String defaultKey = CommonConstant.GET_LOGIN_VERIFICATION_CODE_KEY + StringUtils.trim(phone);
        Object code       = redisUtil.get(defaultKey);
        if (Objects.nonNull(code)) {
            return "验证码已发送至,您的手机请查收.";
        } else {
            try {
                String randomString = SampleRandomUtil.getRandomString(4);
//                String addSmsTemplate = smsUtil.addSmsTemplate();
                String bizId  = smsUtil.sendSms(phone, "SMS_217881424", randomString);
                String result = smsUtil.querySendDetails(bizId);
                if (result.contains("OK")) {
                    redisUtil.set(defaultKey, randomString, 60 * 5);
                }
                return "验证码已发送至,您的手机请查收.";
            } catch (Exception e) {
                log.info("生成注册校验码失败, {}", e);
                throw new CommonAssertException(ApplicationCodes.GET_VERIFICATION_CODE_IS_ERROR);
            }
        }
    }


    private String getDisplayText(boolean isVisible, String lab) {

        if (isVisible) {
            if (StringUtils.isNotEmpty(lab)) {
                return lab;
            } else {
                return "未填写";
            }
        } else {
            return "保密";
        }

    }

}

2. 重构后代码片段

  • UserController.java

/**
 * @author x
 */
@RestController
@RequestMapping("/user")
@Api(value = "用户接口", tags = "用户接口")
public class UserController {

    @Autowired
    private UserQueryService                 userQueryService;
    @Autowired
    private UserApplicationService           userApplicationService;
    @Autowired
    private AuthenticationApplicationService authenticationApplicationService;

    @ApiOperation(value = "登录", notes = "参数: LoginCommand")
    @PostMapping("/login")
    public ResultDTO login(@Valid @RequestBody LoginCommand loginCommand) {
        return authenticationApplicationService.login(loginCommand);
    }

    @ApiOperation(value = "注册", notes = "参数: UserDTO")
    @PostMapping("/register")
    public ResultDTO register(@Valid @RequestBody RegisterCommand registerCommand) {
        return new ResultDTO(userApplicationService.register(registerCommand));
    }

    @ApiOperation(value = "创建邀请码", notes = "参数: 无")
    @PostMapping("/createInvite")
    public ResultDTO createInvite() {
        return new ResultDTO(userApplicationService.createInvite());
    }

    @ApiOperation(value = "验证登录验证码", notes = "参数: 无")
    @PostMapping("/sendLoginValidateCodeByPhone")
    public ResultDTO sendLoginValidateCodeByPhone(@Valid
                                                  @Size(max = 11, min = 11)
                                                  @NotEmpty String phone) {
        return new ResultDTO(userApplicationService.sendLoginValidateCodeByPhone(phone));
    }

    @ApiOperation(value = "查询当前登录人信息", notes = "参数: 无")
    @GetMapping("/current/query")
    public ResultDTO query() {
        return new ResultDTO(userQueryService.queryCurrentUser());
    }
}

  • UserApplicationServiceImpl.java
/**
 * @author xujie
 * @since 2022-01-03
 */
@Service
public class UserApplicationServiceImpl implements UserApplicationService {

    @Autowired
    private UserRepository userRepository;
    @Autowired
    private RedisUtil      redisUtil;
    @Autowired
    private AliSmsUtil     smsUtil;

    @Override
    public String createInvite() {
        return new UserService(userRepository, redisUtil, smsUtil)
                .createInvite();
    }

    @Override
    public boolean register(RegisterCommand registerCommand) {
        User user = UserDTOAssembler.toUser(registerCommand);
        user.setPassword(new Password(user.getPassword().getMd5Password()));
        user.setStatus(new Status(Status.StatusEnum.NORMAL));
        UserService userService = new UserService(userRepository, redisUtil, smsUtil);
        return userService.register(user, registerCommand.getInviteCode());
    }

    @Override
    public String sendLoginValidateCodeByPhone(String phone) {
        return new UserService(redisUtil, smsUtil)
                .sendLoginVerificationCodeByPhone(phone);
    }
}

  • UserService.java
/**
 * DomainService
 *
 * @author xujie
 * @since 2022-01-03
 **/
@Slf4j
public class UserService {

    private UserRepository userRepository;
    private RedisUtil      redisUtil;
    private AliSmsUtil     smsUtil;

    public UserService(UserRepository userRepository, RedisUtil redisUtil, AliSmsUtil smsUtil) {
        this.userRepository = userRepository;
        this.redisUtil = redisUtil;
        this.smsUtil = smsUtil;
    }

    public UserService(RedisUtil redisUtil, AliSmsUtil smsUtil) {
        this.redisUtil = redisUtil;
        this.smsUtil = smsUtil;
    }

    public String createInvite() {
        String                    userUniqueId              = UserCurrentUtil.getUserUniqueId();
        User                      user                      = userRepository.find(new UserUniqueId(userUniqueId));
        CreateInviteSpecification createInviteSpecification = new CreateInviteSpecification();
        if (createInviteSpecification.isSatisfiedBy(user)) {
            String substring     = user.getPhone().getInviteString();
            String inviteCodeKey = UserConstant.USER_INVITE_CODE_KEY + userUniqueId;
            Object code          = redisUtil.get(inviteCodeKey);
            if (Objects.isNull(code)) {
                String randomString      = SampleRandomUtil.getRandomString(userUniqueId, 4);
                String validateCodeValue = substring + randomString;
                redisUtil.set(inviteCodeKey, validateCodeValue, 60 * 5);
                redisUtil.set(UserConstant.INVITE_CODE + validateCodeValue, userUniqueId, 60 * 5);
                return validateCodeValue;
            }
            return code.toString();
        }
        return "";
    }


    public String sendLoginVerificationCodeByPhone(String phone) {
        Optional.ofNullable(phone).orElseThrow(() -> new CommonAssertException(UserConstant.USER_PHONE_NOT_EMPTY));
        String defaultKey = UserConstant.GET_LOGIN_VERIFICATION_CODE_KEY + StringUtils.trim(phone);
        Object code       = redisUtil.get(defaultKey);
        if (Objects.nonNull(code)) {
            return "验证码已发送至,您的手机请查收.";
        } else {
            try {
                String randomString = SampleRandomUtil.getRandomString(4);
                String bizId        = smsUtil.sendSms(phone, "SMS_217881424", randomString);
                String result       = smsUtil.querySendDetails(bizId);
                if (result.contains("OK")) {
                    redisUtil.set(defaultKey, randomString, 60 * 5);
                }
                return "验证码已发送至,您的手机请查收.";
            } catch (Exception e) {
                log.info("生成注册校验码失败, {}", e);
                throw new CommonAssertException(UserConstant.GET_VERIFICATION_CODE_IS_ERROR);
            }
        }
    }

    public boolean register(User user, String inviterCode) {
        UserCreateNotExistSpecification userCreateNotExistSpecification =
                new UserCreateNotExistSpecification(userRepository);
        RegisterInviteCodeSpecification registerInviteCodeSpecification =
                new RegisterInviteCodeSpecification(redisUtil, inviterCode);
        boolean satisfiedBy = userCreateNotExistSpecification
                .and(registerInviteCodeSpecification)
                .isSatisfiedBy(user);
        if (satisfiedBy) {
            return userRepository.store(user);
        }
        return false;
    }
}

重构心得

1. 代码量减少,层次清晰

2. 逻辑清晰,代码可读性强

3. 减少出错率等

posted on 2022-02-08 22:05  站在巨人的肩膀上搬砖  阅读(143)  评论(0)    收藏  举报