XuqmGroup-Server/demo-service/src/main/java/com/xuqm/demo/service/DemoUserService.java
XuqmGroup 526f3cf944 feat: add demo-service, file-service; SDK remote config endpoint; IM fuzzy search
- demo-service (port 8085): auth, user profile, demo-to-IM token bridge
- file-service (port 8086): SHA-256 dedup upload, ImageIO thumbnails, 30-day reclaim
- tenant-service: GET /api/sdk/config?appId returns imWsUrl/fileServiceUrl/features
- im-service: GET /api/im/admin/users/search fuzzy match by userId or nickname

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 16:41:10 +08:00

92 行
3.4 KiB
Java

package com.xuqm.demo.service;
import com.xuqm.common.exception.BusinessException;
import com.xuqm.demo.entity.DemoUserEntity;
import com.xuqm.demo.repository.DemoUserRepository;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
public class DemoUserService {
private final DemoUserRepository userRepository;
private final PasswordEncoder passwordEncoder;
public DemoUserService(DemoUserRepository userRepository, PasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
}
public record UserProfile(String appId, String userId, String nickname, String avatar, String gender) {}
@Transactional(readOnly = true)
public UserProfile getProfile(String appId, String userId) {
DemoUserEntity user = userRepository.findByAppIdAndUserId(appId, userId)
.orElseThrow(() -> new BusinessException(404, "User not found"));
return toProfile(user);
}
@Transactional
public UserProfile updateProfile(String appId, String userId, String nickname, String avatar, String gender) {
DemoUserEntity user = userRepository.findByAppIdAndUserId(appId, userId)
.orElseThrow(() -> new BusinessException(404, "User not found"));
if (nickname != null && !nickname.isBlank()) {
user.setNickname(nickname);
}
if (avatar != null) {
user.setAvatar(avatar.isBlank() ? null : avatar);
}
if (gender != null) {
try {
user.setGender(DemoUserEntity.Gender.valueOf(gender.toUpperCase()));
} catch (IllegalArgumentException e) {
throw new BusinessException(400, "Invalid gender value: " + gender);
}
}
userRepository.save(user);
return toProfile(user);
}
@Transactional
public void resetPassword(String appId, String userId, String oldPassword, String newPassword) {
DemoUserEntity user = userRepository.findByAppIdAndUserId(appId, userId)
.orElseThrow(() -> new BusinessException(404, "User not found"));
if (!passwordEncoder.matches(oldPassword, user.getPasswordHash())) {
throw new BusinessException(401, "Old password is incorrect");
}
if (newPassword == null || newPassword.length() < 6) {
throw new BusinessException(400, "New password must be at least 6 characters");
}
user.setPasswordHash(passwordEncoder.encode(newPassword));
userRepository.save(user);
}
@Transactional(readOnly = true)
public List<UserProfile> searchUsers(String appId, String keyword) {
if (keyword == null || keyword.isBlank()) {
throw new BusinessException(400, "Search keyword must not be blank");
}
return userRepository.searchByKeyword(appId, keyword.trim())
.stream()
.map(this::toProfile)
.toList();
}
private UserProfile toProfile(DemoUserEntity user) {
return new UserProfile(
user.getAppId(),
user.getUserId(),
user.getNickname(),
user.getAvatar(),
user.getGender() != null ? user.getGender().name() : DemoUserEntity.Gender.UNKNOWN.name()
);
}
}