DDD领域驱动设计之代码重构
以用户功能为例
1. 重构前代码片段
/**
* <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;
}
}
/**
* <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. 重构后代码片段
/**
* @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);
}
}
/**
* 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. 减少出错率等