113 lines
4.0 KiB
Java
113 lines
4.0 KiB
Java
package com.example.demo.service;
|
|
|
|
import com.example.demo.dto.UserStatsResponse;
|
|
import com.example.demo.exception.DuplicateEmailException;
|
|
import com.example.demo.exception.ResourceNotFoundException;
|
|
import com.example.demo.model.User;
|
|
import org.springframework.stereotype.Service;
|
|
|
|
import java.util.List;
|
|
import java.util.concurrent.CopyOnWriteArrayList;
|
|
import java.util.concurrent.atomic.AtomicLong;
|
|
import java.util.stream.Collectors;
|
|
|
|
@Service
|
|
public class UserService {
|
|
|
|
private final List<User> users = new CopyOnWriteArrayList<>();
|
|
private final AtomicLong idGenerator = new AtomicLong(1);
|
|
|
|
public UserService() {
|
|
users.add(new User(idGenerator.getAndIncrement(), "Alice Chen", "alice@example.com", 25));
|
|
users.add(new User(idGenerator.getAndIncrement(), "Brandon Li", "brandon@example.com", 30));
|
|
users.add(new User(idGenerator.getAndIncrement(), "Carol Wang", "carol@example.com", 28));
|
|
}
|
|
|
|
public List<User> findAll() {
|
|
return users.stream()
|
|
.sorted((left, right) -> Long.compare(left.getId(), right.getId()))
|
|
.collect(Collectors.toList());
|
|
}
|
|
|
|
public User findById(Long id) {
|
|
return users.stream()
|
|
.filter(user -> user.getId().equals(id))
|
|
.findFirst()
|
|
.orElseThrow(() -> new ResourceNotFoundException("User not found: id=" + id));
|
|
}
|
|
|
|
public List<User> search(String keyword) {
|
|
if (keyword == null || keyword.isBlank()) {
|
|
return findAll();
|
|
}
|
|
|
|
String normalizedKeyword = keyword.trim().toLowerCase();
|
|
return users.stream()
|
|
.filter(user -> user.getName().toLowerCase().contains(normalizedKeyword)
|
|
|| user.getEmail().toLowerCase().contains(normalizedKeyword))
|
|
.sorted((left, right) -> Long.compare(left.getId(), right.getId()))
|
|
.collect(Collectors.toList());
|
|
}
|
|
|
|
public User create(User user) {
|
|
ensureEmailAvailable(user.getEmail(), null);
|
|
User normalized = normalize(user, idGenerator.getAndIncrement());
|
|
users.add(normalized);
|
|
return normalized;
|
|
}
|
|
|
|
public User update(Long id, User user) {
|
|
findById(id);
|
|
ensureEmailAvailable(user.getEmail(), id);
|
|
|
|
User normalized = normalize(user, id);
|
|
for (int index = 0; index < users.size(); index++) {
|
|
if (users.get(index).getId().equals(id)) {
|
|
users.set(index, normalized);
|
|
return normalized;
|
|
}
|
|
}
|
|
|
|
throw new ResourceNotFoundException("User not found: id=" + id);
|
|
}
|
|
|
|
public void delete(Long id) {
|
|
boolean removed = users.removeIf(user -> user.getId().equals(id));
|
|
if (!removed) {
|
|
throw new ResourceNotFoundException("User not found: id=" + id);
|
|
}
|
|
}
|
|
|
|
public UserStatsResponse getStats() {
|
|
long totalUsers = users.size();
|
|
long adults = users.stream().filter(user -> user.getAge() >= 18).count();
|
|
long underThirty = users.stream().filter(user -> user.getAge() < 30).count();
|
|
double averageAge = users.stream()
|
|
.mapToInt(User::getAge)
|
|
.average()
|
|
.orElse(0.0);
|
|
|
|
return new UserStatsResponse(totalUsers, adults, underThirty, averageAge);
|
|
}
|
|
|
|
private void ensureEmailAvailable(String email, Long currentUserId) {
|
|
String normalizedEmail = email == null ? "" : email.trim().toLowerCase();
|
|
boolean exists = users.stream()
|
|
.anyMatch(user -> user.getEmail().equalsIgnoreCase(normalizedEmail)
|
|
&& (currentUserId == null || !user.getId().equals(currentUserId)));
|
|
|
|
if (exists) {
|
|
throw new DuplicateEmailException("A user with email " + normalizedEmail + " already exists.");
|
|
}
|
|
}
|
|
|
|
private User normalize(User user, Long id) {
|
|
return new User(
|
|
id,
|
|
user.getName().trim(),
|
|
user.getEmail().trim().toLowerCase(),
|
|
user.getAge()
|
|
);
|
|
}
|
|
}
|